From 27bf41b8912d51fc555a7cb6c025db9d831c03a7 Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Mon, 26 Aug 2024 17:41:52 +0200 Subject: [PATCH] Refactor the Subscription modal to match the design. --- .../Subscription/PlanUpdateSidePanel.tsx | 350 ++++++++++-------- packages/ui/src/components/Modal/Modal.tsx | 3 +- 2 files changed, 204 insertions(+), 149 deletions(-) diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx index 36df82b6e89..0fd552d60d0 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx @@ -1,6 +1,6 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { isArray } from 'lodash' -import { ChevronRight, ExternalLink } from 'lucide-react' +import { Box, ChevronRight, ExternalLink, Pause } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/router' import { useEffect, useRef, useState } from 'react' @@ -10,7 +10,6 @@ import { billingPartnerLabel } from 'components/interfaces/Billing/Subscription/ import Table from 'components/to-be-cleaned/Table' import AlertError from 'components/ui/AlertError' import { ButtonTooltip } from 'components/ui/ButtonTooltip' -import InformationBox from 'components/ui/InformationBox' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-limit-check-query' import { useOrganizationBillingSubscriptionPreview } from 'data/organizations/organization-billing-subscription-preview' @@ -25,24 +24,13 @@ import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants' import { formatCurrency } from 'lib/helpers' import { pickFeatures, pickFooter, plans as subscriptionsPlans } from 'shared-data/plans' import { useOrgSettingsPageStateSnapshot } from 'state/organization-settings' -import { - AlertDescription_Shadcn_, - AlertTitle_Shadcn_, - Alert_Shadcn_, - Button, - IconCheck, - IconInfo, - Modal, - SidePanel, - cn, -} from 'ui' +import { Alert_Shadcn_, Badge, Button, IconCheck, Modal, SidePanel, WarningIcon, cn } from 'ui' import DowngradeModal from './DowngradeModal' import EnterpriseCard from './EnterpriseCard' import ExitSurveyModal from './ExitSurveyModal' import MembersExceedLimitModal from './MembersExceedLimitModal' import PaymentMethodSelection from './PaymentMethodSelection' import UpgradeSurveyModal from './UpgradeModal' -import PartnerIcon from 'components/ui/PartnerIcon' const PlanUpdateSidePanel = () => { const router = useRouter() @@ -320,14 +308,14 @@ const PlanUpdateSidePanel = () => { setSelectedTier(undefined)} onConfirm={onUpdateSubscription} dialogOverlayProps={{ className: 'pointer-events-none' }} header={`Confirm ${planMeta?.change_type === 'downgrade' ? 'downgrade' : 'upgrade'} to ${subscriptionPlanMeta?.name}`} > - +
{subscriptionPreviewError && ( { /> )} {subscriptionPreviewIsLoading && ( -
+
Estimating monthly costs... @@ -345,167 +333,235 @@ const PlanUpdateSidePanel = () => { {subscriptionPreviewInitialized && (
Item, - + + Item + , + Usage , - Unit Price, - + + Unit Price + , + Cost , ]} body={ <> - {subscriptionPreview.breakdown.map((item) => ( - <> - - - {item.breakdown && item.breakdown.length > 0 && ( - + Project + Project name + + Nano + Micro + + + + + + {formatCurrency(10)} per month + + + + + {formatCurrency(0)} + + {formatCurrency(10)} + + + + + + Any un-paused projects will be charged for compute hours + + + + +
+ + Project + Project name + + + Paused + +
+
+ + + {formatCurrency(10)} per month + + + + + {formatCurrency(0)} + + {formatCurrency(10)} + + +
- {usageFeesExpanded.includes(item.description) && - item.breakdown && - item.breakdown.length > 0 && - item.breakdown.map((project) => ( - - {project.project_name} - - {project.usage} - - - - - ))} - - ))} - - - - Monthly Costs (excluding over-usage and credits) + + + + Credits + + Up to $10 Compute credits - - {formatCurrency( - Math.round( - subscriptionPreview.breakdown.reduce( - (prev, cur) => prev + cur.total_price, - 0 - ) - ) ?? 0 - )} + + {formatCurrency(-10)} + + + + + + + Costs before upgrade + + + {formatCurrency(0)} + + + + + + + +
+ + New monthly cost + + (Excluding over-usage and credits) +
+
+ + + {formatCurrency(35)} +
} >
- } - defaultVisibility={true} - hideCollapse={true} - description={ -
-

- Each project is a dedicated server and database. Paid plans come with $10 of - Compute Credits to cover one project on the default Micro Compute size or - parts of any compute addon. Additional unpaused projects on paid plans will - incur compute usage costs starting at $10 per month, billed hourly. -

- - {subscription?.plan?.id === 'free' && ( -

+ {subscription?.plan?.id === 'free' && ( + +

+ +
+

Mixing paid and non-paid projects in a single organization is not possible. - If you want projects to be on the Free Plan, use self-serve project - transfers.

- )} - -
- - {subscription?.plan?.id === 'free' && ( - - )} +

+ To keep projects on a free plan, move them to another organization. +

+ +
- } - /> + + )}
)} - +
{!billingViaPartner ? ( -
-

- Upon clicking confirm, your monthly invoice will be adjusted and your credit card +

+ +

+ When upgrading to Pro, the monthly invoice will be adjusted and your credit card will be charged immediately. Changing the plan resets your billing cycle and may - result in a prorated charge for previous usage. + result in a prorated charge for the previous usage.

- -
- -
) : (
diff --git a/packages/ui/src/components/Modal/Modal.tsx b/packages/ui/src/components/Modal/Modal.tsx index b32f81a4a17..232dbcb9c8e 100644 --- a/packages/ui/src/components/Modal/Modal.tsx +++ b/packages/ui/src/components/Modal/Modal.tsx @@ -7,14 +7,13 @@ import { Button, ButtonVariantProps } from '../Button/Button' import { Dialog, DialogContent, + DialogDescription, DialogFooter, DialogHeader, DialogSection, DialogSectionSeparator, DialogTitle, DialogTrigger, - DialogDescription, - DialogClose, } from '../shadcn/ui/dialog' export interface ModalProps extends React.ComponentProps {