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