From 793cbd06c227453d0245e28fad411cb863cd91bb Mon Sep 17 00:00:00 2001 From: Oliver Stenbom Date: Wed, 11 Nov 2026 19:22:36 +0100 Subject: [PATCH 1/2] Confirm before inviting someone as an owner Owners can change the plan, manage billing and remove team members, so inviting one now asks for a second, deliberate click. Co-Authored-By: Claude Opus 5.5 --- app/(dashboard)/dashboard/page.tsx | 64 +++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/app/(dashboard)/dashboard/page.tsx b/app/(dashboard)/dashboard/page.tsx index 02bf1bd..9691e35 100644 --- a/app/(dashboard)/dashboard/page.tsx +++ b/app/(dashboard)/dashboard/page.tsx @@ -1,7 +1,14 @@ "use client"; import { Loader2, PlusCircle } from "lucide-react"; -import { Suspense, useActionState, useEffect } from "react"; +import { + type FormEvent, + Suspense, + startTransition, + useActionState, + useEffect, + useState, +} from "react"; import useSWR from "swr"; import { inviteTeamMember, removeTeamMember } from "@/app/(login)/actions"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; @@ -249,6 +256,7 @@ function InviteTeamMember() { ActionState, FormData >(inviteTeamMember, {}); + const [ownerInvite, setOwnerInvite] = useState(null); useEffect(() => { if (inviteState?.id) { @@ -256,13 +264,30 @@ function InviteTeamMember() { } }, [inviteState]); + const sendInvite = (formData: FormData) => { + setOwnerInvite(null); + startTransition(() => inviteAction(formData)); + }; + + // Owners can change the plan and remove members, so inviting one takes a + // second, deliberate click. + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + const formData = new FormData(event.currentTarget); + if (formData.get("role") === "owner") { + setOwnerInvite(formData); + } else { + sendInvite(formData); + } + }; + return ( Invite Team Member -
+
+ {ownerInvite && ( +
+

+ Invite {String(ownerInvite.get("email"))} as an owner? +

+

+ Owners can change the plan, manage billing and remove team + members. +

+
+ + +
+
+ )} {inviteState?.error && (

{inviteState.error}

)} From bf3effd38b7f58349d865806ba3c8cd5deed790d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 11 Nov 2026 18:27:51 +0000 Subject: [PATCH 2/2] Update Playwright Intent steps - repair .intent/tests-intent/invite-owner.spec.ts/should invite a teammate as an owner/invite {email} to the team as an owner.ts: Owner invitations now require an explicit confirmation; confirming the dialog succeeds and displays the existing success message. --- .../invite {email} to the team as an owner.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/.intent/tests-intent/invite-owner.spec.ts/should invite a teammate as an owner/invite {email} to the team as an owner.ts b/.intent/tests-intent/invite-owner.spec.ts/should invite a teammate as an owner/invite {email} to the team as an owner.ts index c19f885..cca9c06 100644 --- a/.intent/tests-intent/invite-owner.spec.ts/should invite a teammate as an owner/invite {email} to the team as an owner.ts +++ b/.intent/tests-intent/invite-owner.spec.ts/should invite a teammate as an owner/invite {email} to the team as an owner.ts @@ -6,5 +6,6 @@ export default async function ({ page, context, request, expect, vars }: StepCon await page.getByRole('textbox', { name: 'Email' }).fill(vars.email); await page.getByRole('radio', { name: 'Owner' }).check(); await page.getByRole('button', { name: 'Invite Member' }).click(); + await page.getByRole('button', { name: 'Yes, invite as owner' }).click(); await expect(page.getByText('Invitation sent successfully')).toBeVisible(); }