diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/organization/billing.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/organization/billing.tsx index ad24846c..7ecbe299 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/organization/billing.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/organization/billing.tsx @@ -15,6 +15,7 @@ import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import { WidgetTable } from '@/components/widget-table'; import { useAppParams } from '@/hooks/useAppParams'; import useWS from '@/hooks/useWS'; +import { showConfirm } from '@/modals'; import { api } from '@/trpc/client'; import type { IServiceOrganization } from '@openpanel/db'; import type { IPolarPrice } from '@openpanel/payments'; @@ -257,12 +258,23 @@ function CheckoutButton({ disabled={disabled !== null || (isActive && !isCanceled)} key={price.id} onClick={() => { - checkout.mutate({ - projectId, - organizationId: organization.id, - productPriceId: price!.id, - productId: price.productId, - }); + const createCheckout = () => + checkout.mutate({ + projectId, + organizationId: organization.id, + productPriceId: price!.id, + productId: price.productId, + }); + + if (organization.subscriptionStatus === 'active') { + showConfirm({ + title: 'Are you sure?', + text: `You're about the change your subscription.`, + onConfirm: () => createCheckout(), + }); + } else { + createCheckout(); + } }} loading={checkout.isLoading} className="w-28" diff --git a/packages/trpc/src/routers/subscription.ts b/packages/trpc/src/routers/subscription.ts index 8c21aee3..d76725ba 100644 --- a/packages/trpc/src/routers/subscription.ts +++ b/packages/trpc/src/routers/subscription.ts @@ -53,16 +53,25 @@ export const subscriptionRouter = createTRPCRouter({ organization.subscriptionId && organization.subscriptionStatus === 'active' ) { - if (organization.subscriptionCanceledAt) { - await reactivateSubscription(organization.subscriptionId); + const existingProduct = organization.subscriptionProductId + ? await getProduct(organization.subscriptionProductId) + : null; + + // If the existing product is free, cancel the subscription and then jump to the checkout + if (existingProduct?.prices.some((p) => p.amountType === 'free')) { + await cancelSubscription(organization.subscriptionId); } else { + if (organization.subscriptionCanceledAt) { + await reactivateSubscription(organization.subscriptionId); + return null; + } + await changeSubscription( organization.subscriptionId, input.productId, ); + return null; } - - return null; } const checkout = await createCheckout({