From 3f5808704354f0bf1bc056b8831402e15b3b830e Mon Sep 17 00:00:00 2001 From: Eliezer Steinbock <3090527+elie222@users.noreply.github.com> Date: Fri, 5 Sep 2025 01:37:00 +0300 Subject: [PATCH] Fix duplicate pending and account premium --- .../settings/MultiAccountSection.tsx | 12 +++++++++++- apps/web/ee/billing/stripe/sync-stripe.ts | 19 +++++++++++++++---- version.txt | 2 +- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/web/app/(app)/[emailAccountId]/settings/MultiAccountSection.tsx b/apps/web/app/(app)/[emailAccountId]/settings/MultiAccountSection.tsx index f783031af9..b68ad1da65 100644 --- a/apps/web/app/(app)/[emailAccountId]/settings/MultiAccountSection.tsx +++ b/apps/web/app/(app)/[emailAccountId]/settings/MultiAccountSection.tsx @@ -143,7 +143,17 @@ function MultiAccountForm({ resolver: zodResolver(saveMultiAccountPremiumBody), defaultValues: { emailAddresses: emailAddresses?.length - ? [...emailAddresses, ...pendingInvites.map((email) => ({ email }))] + ? (() => { + // Deduplicate to prevent showing the same email twice + const existingEmails = new Set(emailAddresses.map((e) => e.email)); + const uniquePendingInvites = pendingInvites.filter( + (email) => !existingEmails.has(email), + ); + return [ + ...emailAddresses, + ...uniquePendingInvites.map((email) => ({ email })), + ]; + })() : [{ email: "" }], }, }); diff --git a/apps/web/ee/billing/stripe/sync-stripe.ts b/apps/web/ee/billing/stripe/sync-stripe.ts index e73b315558..1ae3a9e33b 100644 --- a/apps/web/ee/billing/stripe/sync-stripe.ts +++ b/apps/web/ee/billing/stripe/sync-stripe.ts @@ -122,7 +122,8 @@ export async function syncStripeDataToDb({ pendingInvites: true, users: { select: { - _count: true, + email: true, + _count: { select: { emailAccounts: true } }, }, }, }, @@ -149,17 +150,27 @@ export async function syncStripeDataToDb({ async function syncSeats( premium: Prisma.PremiumGetPayload<{ select: { - users: { select: { _count: { select: { emailAccounts: true } } } }; + users: { + select: { email: true; _count: { select: { emailAccounts: true } } }; + }; pendingInvites: true; stripeSubscriptionItemId: true; }; }>, ) { try { - // total seats = premium users + pending invites + // Get all connected user emails + const connectedUserEmails = new Set(premium.users.map((u) => u.email)); + + // Filter out pending invites that are already connected users to avoid double counting + const uniquePendingInvites = (premium.pendingInvites || []).filter( + (email) => !connectedUserEmails.has(email), + ); + + // total seats = premium users + unique pending invites (excluding duplicates) const totalSeats = sumBy(premium.users, (u) => u._count.emailAccounts) + - (premium.pendingInvites?.length || 0); + uniquePendingInvites.length; await updateAccountSeatsForPremium(premium, totalSeats); } catch (error) { diff --git a/version.txt b/version.txt index cb19d3bb1b..351ebb8536 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v2.8.10 +v2.8.11