feat: edit guest from guest groups
This commit is contained in:
@@ -6,13 +6,26 @@ import { redirect } from "next/navigation"
|
||||
import { auth } from "@/auth"
|
||||
import { isAdminEmail } from "@/lib/admin-auth"
|
||||
import { deleteInvitationGroup } from "@/lib/db/queries/invitations"
|
||||
import {
|
||||
deleteInvitationMember,
|
||||
updateInvitationMemberName,
|
||||
} from "@/lib/db/queries/members"
|
||||
import { deleteUploadObject } from "@/lib/storage/uploads"
|
||||
import { deleteInvitationSchema } from "@/lib/validation/invitation"
|
||||
import {
|
||||
deleteInvitationMemberSchema,
|
||||
updateInvitationMemberSchema,
|
||||
} from "@/lib/validation/member"
|
||||
|
||||
export interface DeleteInvitationActionState {
|
||||
error: string | null
|
||||
}
|
||||
|
||||
export interface MemberActionState {
|
||||
error: string | null
|
||||
success: boolean
|
||||
}
|
||||
|
||||
export async function deleteInvitationAction(
|
||||
_previousState: DeleteInvitationActionState,
|
||||
formData: FormData,
|
||||
@@ -62,3 +75,82 @@ export async function deleteInvitationAction(
|
||||
revalidatePath("/admin/guests")
|
||||
redirect("/admin/guests?deleted=1")
|
||||
}
|
||||
|
||||
export async function updateInvitationMemberAction(
|
||||
_previousState: MemberActionState,
|
||||
formData: FormData,
|
||||
): Promise<MemberActionState> {
|
||||
const session = await auth()
|
||||
const adminEmail = session?.user?.email
|
||||
|
||||
if (!isAdminEmail(adminEmail)) {
|
||||
return { error: "You are not allowed to edit guest members.", success: false }
|
||||
}
|
||||
const authorizedAdminEmail = adminEmail ?? ""
|
||||
|
||||
const parsed = updateInvitationMemberSchema.safeParse({
|
||||
invitationId: formData.get("invitationId")?.toString(),
|
||||
memberId: formData.get("memberId")?.toString(),
|
||||
name: formData.get("name")?.toString(),
|
||||
})
|
||||
|
||||
if (!parsed.success) return { error: "Enter a valid member name.", success: false }
|
||||
|
||||
try {
|
||||
const result = await updateInvitationMemberName({
|
||||
...parsed.data,
|
||||
adminEmail: authorizedAdminEmail,
|
||||
})
|
||||
|
||||
if (result.status === "not_found") {
|
||||
return { error: "This guest member was not found.", success: false }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to update invitation member", error)
|
||||
return { error: "Could not update this guest member. Please try again.", success: false }
|
||||
}
|
||||
|
||||
revalidatePath(`/admin/guests/${parsed.data.invitationId}`)
|
||||
revalidatePath("/admin/guests")
|
||||
revalidatePath("/admin")
|
||||
return { error: null, success: true }
|
||||
}
|
||||
|
||||
export async function deleteInvitationMemberAction(
|
||||
_previousState: MemberActionState,
|
||||
formData: FormData,
|
||||
): Promise<MemberActionState> {
|
||||
const session = await auth()
|
||||
const adminEmail = session?.user?.email
|
||||
|
||||
if (!isAdminEmail(adminEmail)) {
|
||||
return { error: "You are not allowed to delete guest members.", success: false }
|
||||
}
|
||||
const authorizedAdminEmail = adminEmail ?? ""
|
||||
|
||||
const parsed = deleteInvitationMemberSchema.safeParse({
|
||||
invitationId: formData.get("invitationId")?.toString(),
|
||||
memberId: formData.get("memberId")?.toString(),
|
||||
})
|
||||
|
||||
if (!parsed.success) return { error: "Could not delete this guest member.", success: false }
|
||||
|
||||
try {
|
||||
const result = await deleteInvitationMember({ ...parsed.data, adminEmail: authorizedAdminEmail })
|
||||
|
||||
if (result.status === "not_found") {
|
||||
return { error: "This guest member was already removed.", success: false }
|
||||
}
|
||||
if (result.status === "last_member") {
|
||||
return { error: "A guest group must have at least one member.", success: false }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to delete invitation member", error)
|
||||
return { error: "Could not delete this guest member. Please try again.", success: false }
|
||||
}
|
||||
|
||||
revalidatePath(`/admin/guests/${parsed.data.invitationId}`)
|
||||
revalidatePath("/admin/guests")
|
||||
revalidatePath("/admin")
|
||||
return { error: null, success: true }
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { notFound } from "next/navigation"
|
||||
import { CopyInviteButton } from "@/components/admin/copy-invite-button"
|
||||
import { DeleteInvitationDialog } from "@/components/admin/delete-invitation-dialog"
|
||||
import { InvitationLanguageSelect } from "@/components/admin/invitation-language-select"
|
||||
import { MemberManagement } from "@/components/admin/member-management"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
@@ -195,6 +196,7 @@ export default async function GuestDetailPage({
|
||||
<TableHead>Attending</TableHead>
|
||||
<TableHead>Meal</TableHead>
|
||||
<TableHead>Dietary restrictions</TableHead>
|
||||
<TableHead className="text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -205,6 +207,14 @@ export default async function GuestDetailPage({
|
||||
<TableCell>{formatBoolean(member.attending)}</TableCell>
|
||||
<TableCell>{member.meal_preference ?? "—"}</TableCell>
|
||||
<TableCell>{member.dietary_restrictions ?? "—"}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<MemberManagement
|
||||
invitationId={detail.invitation.id}
|
||||
memberId={member.id}
|
||||
memberName={member.name}
|
||||
canDelete={detail.members.length > 1}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
|
||||
Reference in New Issue
Block a user