my-fullstack-ai-platform/app/dashboard/settings/team/actions.ts

119 lines
3.3 KiB
TypeScript

"use server";
import { createClient } from "@/lib/supabase/server";
import { revalidatePath } from "next/cache";
export type InviteStatus = {
success?: boolean;
error?: string;
message?: string;
};
export async function inviteUser(prevState: InviteStatus | null, formData: FormData): Promise<InviteStatus> {
const email = formData.get("email") as string;
if (!email) {
return { error: "Email is required" };
}
try {
const supabase = await createClient();
const { data: userData, error: userError } = await supabase.auth.getUser();
if (userError || !userData.user) {
return { error: "Unauthorized" };
}
const { data: profile } = await supabase
.from("profiles")
.select("organization_id, role")
.eq("id", userData.user.id)
.single();
if (!profile || profile.role !== "owner" || !profile.organization_id) {
return { error: "Only organization owners can invite new members" };
}
// Check if user is already a member
const { data: existingMember } = await supabase
.from("profiles")
.select("id")
.eq("email", email)
.eq("organization_id", profile.organization_id)
.maybeSingle();
if (existingMember) {
return { error: "User is already a member of this organization" };
}
// Check if there's already a pending invitation
const { data: existingInvitation } = await supabase
.from("invitations")
.select("id")
.eq("email", email)
.eq("organization_id", profile.organization_id)
.eq("status", "pending")
.gt("expires_at", new Date().toISOString())
.maybeSingle();
if (existingInvitation) {
return { error: "An invitation is already pending for this email address" };
}
const { error: inviteError } = await supabase
.from("invitations")
.insert([
{
email,
organization_id: profile.organization_id,
invited_by: userData.user.id,
},
]);
if (inviteError) {
console.error("Error creating invitation:", inviteError);
return { error: "Failed to create invitation" };
}
revalidatePath("/dashboard/settings/team");
return { success: true, message: "Invitation sent successfully" };
} catch (error) {
console.error("Unexpected error inviting user:", error);
return { error: "An unexpected error occurred" };
}
}
export async function revokeInvitation(formData: FormData) {
const id = formData.get("id") as string;
if (!id) {
throw new Error("Invitation ID is required");
}
const supabase = await createClient();
const { data: userData, error: userError } = await supabase.auth.getUser();
if (userError || !userData.user) {
throw new Error("Unauthorized");
}
const { data: profile } = await supabase
.from("profiles")
.select("organization_id, role")
.eq("id", userData.user.id)
.single();
if (!profile || profile.role !== "owner" || !profile.organization_id) {
throw new Error("Only organization owners can revoke invitations");
}
const { error: deleteError } = await supabase
.from("invitations")
.delete()
.match({ id, organization_id: profile.organization_id });
if (deleteError) {
console.error("Error revoking invitation:", deleteError);
throw new Error("Failed to revoke invitation");
}
revalidatePath("/dashboard/settings/team");
}