UpgradePlanButton.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { PermissionAction } from '@supabase/shared-types/out/constants'
  2. import { useFlag, useParams } from 'common'
  3. import Link from 'next/link'
  4. import { PropsWithChildren } from 'react'
  5. import { Button } from 'ui'
  6. import { ButtonTooltip } from './ButtonTooltip'
  7. import { RequestUpgradeToBillingOwners } from './RequestUpgradeToBillingOwners'
  8. import { SupportLink } from '@/components/interfaces/Support/SupportLink'
  9. import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
  10. import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
  11. import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
  12. export const PLAN_REQUEST_EMPTY_PLACEHOLDER =
  13. '<Specify which plan to upgrade to: Pro | Team | Enterprise>'
  14. interface UpgradePlanButtonProps {
  15. /** Stick to camel case for consistency */
  16. source: string
  17. variant?: 'default' | 'primary'
  18. plan?: 'Pro' | 'Team' | 'Enterprise'
  19. addon?: 'pitr' | 'customDomain' | 'ipv4' | 'spendCap' | 'computeSize'
  20. /** Used in the default message template for request upgrade dialog, e.g: "Upgrade to ..." */
  21. featureProposition?: string
  22. disabled?: boolean
  23. className?: string
  24. slug?: string
  25. onClick?: () => void
  26. }
  27. /**
  28. * If `billingAll` is enabled, links to upgrade paths (e.g organization settings, addons).
  29. *
  30. * Otherwise, links to support form instead
  31. */
  32. export const UpgradePlanButton = ({
  33. source,
  34. variant: type = 'primary',
  35. plan = 'Pro',
  36. addon,
  37. featureProposition,
  38. disabled,
  39. children,
  40. className,
  41. slug: slugParam,
  42. onClick,
  43. }: PropsWithChildren<UpgradePlanButtonProps>) => {
  44. const { ref } = useParams()
  45. const { data: organization } = useSelectedOrganizationQuery()
  46. const isFreePlan = organization?.plan?.id === 'free'
  47. const slug = slugParam ?? organization?.slug ?? '_'
  48. const projectUpdateDisabled = useFlag('disableProjectCreationAndUpdate')
  49. const { billingAll } = useIsFeatureEnabled(['billing:all'])
  50. const { can: canUpdateSubscription } = useAsyncCheckPermissions(
  51. PermissionAction.BILLING_WRITE,
  52. 'stripe.subscriptions',
  53. undefined,
  54. { organizationSlug: slug }
  55. )
  56. const subject = `Enquiry to upgrade ${!!plan ? `to ${plan} ` : ''}plan for organization`
  57. const message = `Name: ${organization?.name}\nSlug: ${slug}\nRequested plan: ${plan ?? PLAN_REQUEST_EMPTY_PLACEHOLDER}`
  58. const isRequestingToDisableSpendCap = addon === 'spendCap'
  59. const isOnPaidPlanAndRequestingToPurchaseAddon = !isFreePlan && !!addon
  60. // [Joshen] URL for button based on the "upgrade request" and the org's plan. Falls back to URL for opening subscription plan
  61. const href = isRequestingToDisableSpendCap
  62. ? `/org/${slug ?? '_'}/billing?panel=costControl&source=${source}`
  63. : isOnPaidPlanAndRequestingToPurchaseAddon
  64. ? addon === 'computeSize'
  65. ? `/project/${ref ?? '_'}/settings/compute-and-disk`
  66. : `/project/${ref ?? '_'}/settings/addons?panel=${addon}&source=${source}`
  67. : `/org/${slug ?? '_'}/billing?panel=subscriptionPlan&source=${source}`
  68. const linkChildren =
  69. children ||
  70. (isOnPaidPlanAndRequestingToPurchaseAddon
  71. ? addon === 'computeSize'
  72. ? 'Change compute size'
  73. : 'Enable add-on'
  74. : `Upgrade to ${plan}`)
  75. const link = billingAll ? (
  76. <Link href={href}>{linkChildren}</Link>
  77. ) : (
  78. <SupportLink queryParams={{ orgSlug: slug, category: 'Plan_upgrade', subject, message }}>
  79. {linkChildren}
  80. </SupportLink>
  81. )
  82. if (!canUpdateSubscription) {
  83. return (
  84. <RequestUpgradeToBillingOwners
  85. plan={plan}
  86. addon={addon}
  87. featureProposition={featureProposition}
  88. className={className}
  89. type={type}
  90. >
  91. {children}
  92. </RequestUpgradeToBillingOwners>
  93. )
  94. }
  95. if (projectUpdateDisabled) {
  96. return (
  97. <ButtonTooltip
  98. disabled
  99. type={type}
  100. className={className}
  101. tooltip={{
  102. content: {
  103. side: 'bottom',
  104. text: 'Plan changes are currently disabled, our engineers are working on a fix',
  105. },
  106. }}
  107. >
  108. {linkChildren}
  109. </ButtonTooltip>
  110. )
  111. }
  112. return (
  113. <Button asChild type={type} disabled={disabled} className={className} onClick={onClick}>
  114. {link}
  115. </Button>
  116. )
  117. }