Skip to content
42 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.

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)1import { redirect } from "react-router";
2
3import type { User, WorkspaceInvitation } from "@g1t/contracts";
4
5import { identity } from "./services.server";
6import { rememberWorkspace } from "./workspace-choice";
7import { safeNext } from "./next";
8
9/** The workspace invitations waiting for `user`'s answer; empty when they cannot be read. */
10export async function loadInvitations(user: User): Promise<WorkspaceInvitation[]> {
11 if (!user.verified) return [];
12 return identity.listInvitations(user).catch(() => []);
13}
14
15/** What answering an invitation says back, when it does not move on. */
16export type InvitationAnswer = { invitationError?: string; invitationId?: string; declined?: string } | undefined;
17
18/**
19 * Answers an invitation from a posted form (`intent` accept or decline,
20 * `id`). Accepting lands in the workspace joined, made the one the sidebar
21 * is about, or in `next` when they were on their way somewhere. Undefined
22 * for any other intent.
23 */
24export async function answerInvitation(user: User, form: FormData, request: Request): Promise<InvitationAnswer> {
25 const intent = form.get("intent");
26 const id = String(form.get("id") ?? "");
27 if (intent === "accept-invitation") {
28 const result = await identity.acceptInvitation(user, id);
29 if (!result.ok) return { invitationError: result.error.message, invitationId: id };
30 const secure = new URL(request.url).protocol === "https:";
31 const next = safeNext(String(form.get("next") ?? ""));
32 throw redirect(next !== "/" ? next : `/${result.value}`, {
33 headers: { "set-cookie": rememberWorkspace(result.value, secure) },
34 });
35 }
36 if (intent === "decline-invitation") {
37 const result = await identity.declineInvitation(user, id);
38 if (!result.ok) return { invitationError: result.error.message, invitationId: id };
39 return { declined: String(form.get("workspace") ?? "") };
40 }
41 return undefined;
42}

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