diff --git a/apps/code/src/app/dashboard/components/DevPassInvoices.tsx b/apps/code/src/app/dashboard/components/DevPassInvoices.tsx index 315e7d3b3c..8bcf28cd84 100644 --- a/apps/code/src/app/dashboard/components/DevPassInvoices.tsx +++ b/apps/code/src/app/dashboard/components/DevPassInvoices.tsx @@ -204,12 +204,14 @@ function RefundButton({ invoice }: { invoice: Invoice }) { - {isResetPass ? "Refund this Reset Pass?" : "Refund this payment?"} + {isResetPass + ? "Refund this Reset Pass?" + : "Refund and cancel your DevPass?"} {isResetPass ? `${formatAmount(invoice.amount, invoice.currency)} will be refunded to your payment method and the unused pass removed from your passport. Your DevPass plan is not affected. This cannot be undone.` - : `${formatAmount(invoice.amount, invoice.currency)} will be refunded to your payment method and your DevPass will be cancelled immediately. This cannot be undone.`} + : `Refunding cancels your subscription completely: ${formatAmount(invoice.amount, invoice.currency)} goes back to your payment method and your DevPass ends right away — not at the end of the billing period — so the rest of this cycle's credits are lost. To use DevPass again you would have to subscribe from scratch. This cannot be undone.`} diff --git a/apps/playground/src/components/pricing/chat-billing-history.tsx b/apps/playground/src/components/pricing/chat-billing-history.tsx index 169534d04c..5051f0b269 100644 --- a/apps/playground/src/components/pricing/chat-billing-history.tsx +++ b/apps/playground/src/components/pricing/chat-billing-history.tsx @@ -245,18 +245,21 @@ function RefundButton({ - Refund this payment? + + {isPlanPayment(transaction.type) + ? "Refund and cancel your membership?" + : "Refund this payment?"} + - {formatAmount(transaction.amount, transaction.currency)} will be - refunded to your payment method.{" "} {isPlanPayment(transaction.type) - ? "Your chat plan will be cancelled immediately. " - : "The purchased credits will be removed from your balance. "} - This cannot be undone. + ? `Refunding cancels your Lounge membership completely: ${formatAmount(transaction.amount, transaction.currency)} goes back to your payment method and your access ends right away — not at the end of the billing period — so the rest of this cycle's credits are lost. To keep using the Lounge you would have to subscribe again. This cannot be undone.` + : `${formatAmount(transaction.amount, transaction.currency)} will be refunded to your payment method. The purchased credits will be removed from your balance. This cannot be undone.`} - Cancel + + {isPlanPayment(transaction.type) ? "Keep my membership" : "Cancel"} + refundMutation.mutate({ @@ -266,7 +269,9 @@ function RefundButton({ }) } > - Request refund + {isPlanPayment(transaction.type) + ? "Refund and cancel" + : "Request refund"} diff --git a/apps/ui/src/components/billing/transactions-client.tsx b/apps/ui/src/components/billing/transactions-client.tsx index 2573d0023f..51b0e21b1a 100644 --- a/apps/ui/src/components/billing/transactions-client.tsx +++ b/apps/ui/src/components/billing/transactions-client.tsx @@ -59,7 +59,12 @@ interface Transaction { | "credit_gift" | "subscription_start" | "subscription_cancel" - | "subscription_end"; + | "subscription_end" + | "dev_plan_start" + | "dev_plan_renewal" + | "dev_plan_reset_pass" + | "chat_plan_start" + | "chat_plan_renewal"; creditAmount: string | null; amount: string | null; status: "pending" | "completed" | "failed"; @@ -83,6 +88,17 @@ const REFUND_INELIGIBILITY_COPY: Record< pass_already_used: "This Reset Pass has already been redeemed", }; +// Refunding a plan payment does not just return the money: the webhook cancels +// the Stripe subscription outright, so the dialog has to say so. +function isPlanPayment(type: Transaction["type"]): boolean { + return ( + type === "dev_plan_start" || + type === "dev_plan_renewal" || + type === "chat_plan_start" || + type === "chat_plan_renewal" + ); +} + function RefundButton({ orgId, transaction, @@ -114,8 +130,9 @@ function RefundButton({ } toast({ title: "Refund processing", - description: - "Your refund has been submitted and will appear in your transaction history shortly.", + description: isPlanPayment(transaction.type) + ? "Your subscription has been cancelled and the refund will appear in your transaction history shortly." + : "Your refund has been submitted and will appear in your transaction history shortly.", }); router.refresh(); } catch { @@ -164,18 +181,37 @@ function RefundButton({ - Refund this purchase? + + {isPlanPayment(transaction.type) + ? "Refund and cancel your subscription?" + : "Refund this purchase?"} + - ${Number(transaction.amount ?? 0).toFixed(2)} will be refunded to - your original payment method and{" "} - {Number(transaction.creditAmount ?? 0).toFixed(2)} credits will be - removed from your balance. This cannot be undone. + {isPlanPayment(transaction.type) + ? `Refunding cancels your subscription completely: $${Number( + transaction.amount ?? 0, + ).toFixed( + 2, + )} goes back to your original payment method and the plan ends right away — not at the end of the billing period — so the rest of this cycle's credits are lost. To use it again you would have to subscribe from scratch. This cannot be undone.` + : transaction.type === "dev_plan_reset_pass" + ? `$${Number(transaction.amount ?? 0).toFixed(2)} will be refunded to your original payment method and the unused Reset Pass removed from your account. Your plan is not affected. This cannot be undone.` + : `$${Number(transaction.amount ?? 0).toFixed(2)} will be refunded to your original payment method and ${Number( + transaction.creditAmount ?? 0, + ).toFixed( + 2, + )} credits will be removed from your balance. This cannot be undone.`} - Cancel + + {isPlanPayment(transaction.type) + ? "Keep my subscription" + : "Cancel"} + - Request refund + {isPlanPayment(transaction.type) + ? "Refund and cancel" + : "Request refund"}