| 1 | import { redirect } from "react-router"; |
| 2 | |
| 3 | import type { User, WorkspaceInvitation } from "@g1t/contracts"; |
| 4 | |
| 5 | import { identity } from "./services.server"; |
| 6 | import { rememberWorkspace } from "./workspace-choice"; |
| 7 | import { safeNext } from "./next"; |
| 8 | |
| 9 | /** The workspace invitations waiting for `user`'s answer; empty when they cannot be read. */ |
| 10 | export 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. */ |
| 16 | export 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 | */ |
| 24 | export 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 | } |