Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions web/actions/members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,15 @@ export async function inviteMember(input: {
}) {
const session = await requireAdminSession();

const parsed = inviteMemberSchema.parse(input);
const email = parsed.email.toLowerCase();
const parsed = inviteMemberSchema.safeParse(input);
if (!parsed.success) {
return {
success: false as const,
error: parsed.error.issues[0]?.message ?? "Invalid invitation details",
};
}

const email = parsed.data.email.toLowerCase();

const existingUser = await db
.select({ id: user.id })
Expand All @@ -149,7 +156,10 @@ export async function inviteMember(input: {
.limit(1);

if (existingUser.length > 0) {
throw new Error("A member with this email already exists");
return {
success: false as const,
error: "A member with this email already exists",
};
}

await db
Expand Down Expand Up @@ -186,7 +196,7 @@ export async function inviteMember(input: {
await db.insert(memberInvitations).values({
id: randomUUID(),
email,
role: parsed.role,
role: parsed.data.role,
tokenHash: hashInviteToken(token),
status: "pending",
invitedByUserId: session.user.id,
Expand All @@ -196,12 +206,12 @@ export async function inviteMember(input: {
const emailSent = await sendMemberInviteEmail({
to: email,
inviterName: session.user.name,
role: parsed.role,
role: parsed.data.role,
inviteUrl,
});

revalidatePath("/dashboard/settings");
return { success: true, inviteUrl, emailSent };
return { success: true as const, inviteUrl, emailSent };
}

export async function revokeInvitation(invitationId: string) {
Expand Down
5 changes: 5 additions & 0 deletions web/components/settings/member-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ export function MemberSettings({ initialMembers, initialInvitations }: Props) {
setIsInviting(true);
try {
const result = await inviteMember({ email, role });
if (!result.success) {
toast.error(result.error);
return;
}

setEmail("");
toast.success(
result.emailSent ? "Invitation sent" : "Invitation created",
Expand Down
Loading