| 1 | /** |
| 2 | * What the Invite dialog and the Invitations page post, answered the same |
| 3 | * way from whichever page they are on (Members, Invitations): inviting |
| 4 | * someone, sending an invitation again, and revoking one. Identity checks |
| 5 | * the owner, the plan and the invite allowance again. Answering an |
| 6 | * invitation of your own is lib/invitations.server.ts. |
| 7 | */ |
| 8 | import type { User } from "@g1t/contracts"; |
| 9 | |
| 10 | import type { InvitationResult, InviteResult } from "./invites"; |
| 11 | import { inviteTarget } from "./people-search"; |
| 12 | import { identity } from "./services.server"; |
| 13 | |
| 14 | /** |
| 15 | * Invites whoever the form names (`member`: a username or an address) with |
| 16 | * `role` and an optional `message`. Nobody joins without saying yes: a |
| 17 | * username or an address gets an invitation to accept or decline. |
| 18 | */ |
| 19 | export async function inviteFromForm(user: User, slug: string, form: FormData): Promise<InviteResult> { |
| 20 | const member = String(form.get("member") ?? "").trim(); |
| 21 | const who = inviteTarget(member); |
| 22 | if (!who) return { error: "Enter a g1t username or an email address.", outOfInvites: false }; |
| 23 | const role = form.get("role") === "owner" ? "owner" : "member"; |
| 24 | const message = String(form.get("message") ?? "").trim() || null; |
| 25 | const result = await identity.inviteMember(user, slug, { ...who, role, message }); |
| 26 | if (!result.ok) return { error: result.error.message, outOfInvites: result.error.code === "limit" }; |
| 27 | return { invited: "email" in who ? who.email : `@${who.username}`, outOfInvites: false }; |
| 28 | } |
| 29 | |
| 30 | /** `action=revoke-invite` or `action=resend-invite`, with the invitation's `id`; null for anything else. */ |
| 31 | export async function invitationFromForm(user: User, slug: string, form: FormData): Promise<InvitationResult | null> { |
| 32 | const action = form.get("action"); |
| 33 | const id = String(form.get("id") ?? "").trim(); |
| 34 | if (action !== "revoke-invite" && action !== "resend-invite") return null; |
| 35 | if (!id) return { error: "Which invitation?", id }; |
| 36 | const result = |
| 37 | action === "revoke-invite" ? await identity.revokeWorkspaceInvite(user, slug, id) : await identity.resendWorkspaceInvite(user, slug, id); |
| 38 | if (!result.ok) return { error: result.error.message, id }; |
| 39 | return { done: action === "revoke-invite" ? "revoked" : "resent", id }; |
| 40 | } |