feat: edit guest from guest groups
Deploy On Server / Prepare Repository Remotely (push) Successful in 15s
Deploy On Server / Docker Compose Up (push) Successful in 19s
Deploy On Server / Prune Images (push) Successful in 2s
Deploy On Server / Remove .env File (push) Successful in 2s

This commit is contained in:
Raul Lugo
2026-09-18 23:43:16 +02:00
parent 77183bc5d6
commit 0ff76deb3a
5 changed files with 413 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
"use client"
import { useState } from "react"
import { useRouter } from "next/navigation"
import {
deleteInvitationMemberAction,
updateInvitationMemberAction,
} from "@/app/admin/guests/[id]/actions"
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
interface MemberManagementProps {
invitationId: string
memberId: string
memberName: string
canDelete: boolean
}
function SubmitButton({ children, variant = "default", pending }: { children: React.ReactNode; variant?: "default" | "destructive"; pending: boolean }) {
return (
<Button type="submit" variant={variant} disabled={pending}>
{pending ? "Saving..." : children}
</Button>
)
}
export function MemberManagement({
invitationId,
memberId,
memberName,
canDelete,
}: MemberManagementProps) {
const router = useRouter()
const [editOpen, setEditOpen] = useState(false)
const [deleteOpen, setDeleteOpen] = useState(false)
const [name, setName] = useState(memberName)
const [editError, setEditError] = useState<string | null>(null)
const [deleteError, setDeleteError] = useState<string | null>(null)
const [pendingAction, setPendingAction] = useState<"edit" | "delete" | null>(null)
async function submitEdit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault()
setPendingAction("edit")
setEditError(null)
const result = await updateInvitationMemberAction({ error: null, success: false }, new FormData(event.currentTarget))
setPendingAction(null)
if (result.error) {
setEditError(result.error)
return
}
setEditOpen(false)
router.refresh()
}
async function submitDelete(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault()
setPendingAction("delete")
setDeleteError(null)
const result = await deleteInvitationMemberAction({ error: null, success: false }, new FormData(event.currentTarget))
setPendingAction(null)
if (result.error) {
setDeleteError(result.error)
return
}
setDeleteOpen(false)
router.refresh()
}
return (
<div className="flex flex-wrap gap-2">
<AlertDialog open={editOpen} onOpenChange={setEditOpen}>
<AlertDialogTrigger asChild>
<Button type="button" size="sm" variant="outline">Edit</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<form onSubmit={submitEdit} className="space-y-4">
<input type="hidden" name="invitationId" value={invitationId} />
<input type="hidden" name="memberId" value={memberId} />
<AlertDialogHeader>
<AlertDialogTitle>Edit guest member</AlertDialogTitle>
<AlertDialogDescription>Update the member&apos;s name.</AlertDialogDescription>
</AlertDialogHeader>
<Input
name="name"
value={name}
onChange={(event) => setName(event.target.value)}
aria-label="Member name"
autoFocus
maxLength={200}
required
/>
{editError ? <p className="text-sm text-destructive">{editError}</p> : null}
<AlertDialogFooter>
<AlertDialogCancel type="button">Cancel</AlertDialogCancel>
<SubmitButton pending={pendingAction === "edit"}>Save changes</SubmitButton>
</AlertDialogFooter>
</form>
</AlertDialogContent>
</AlertDialog>
{canDelete ? (
<AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>
<AlertDialogTrigger asChild>
<Button type="button" size="sm" variant="destructive">Delete</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<form onSubmit={submitDelete} className="space-y-4">
<input type="hidden" name="invitationId" value={invitationId} />
<input type="hidden" name="memberId" value={memberId} />
<AlertDialogHeader>
<AlertDialogTitle>Delete {memberName}?</AlertDialogTitle>
<AlertDialogDescription>
This removes the member from the invitation. If they are the primary contact,
another member will become primary.
</AlertDialogDescription>
</AlertDialogHeader>
{deleteError ? <p className="text-sm text-destructive">{deleteError}</p> : null}
<AlertDialogFooter>
<AlertDialogCancel type="button">Cancel</AlertDialogCancel>
<SubmitButton variant="destructive" pending={pendingAction === "delete"}>Delete member</SubmitButton>
</AlertDialogFooter>
</form>
</AlertDialogContent>
</AlertDialog>
) : null}
</div>
)
}