Skip to content

Commit

Permalink
[fix] add aws subscription to UI (#210)
Browse files Browse the repository at this point in the history
  • Loading branch information
sijav authored May 15, 2024
1 parent d40d9f4 commit 18ab690
Show file tree
Hide file tree
Showing 21 changed files with 1,200 additions and 758 deletions.
196 changes: 119 additions & 77 deletions src/locales/de-DE/messages.po

Large diffs are not rendered by default.

188 changes: 115 additions & 73 deletions src/locales/en-US/messages.po

Large diffs are not rendered by default.

555 changes: 0 additions & 555 deletions src/pages/panel/workspace-settings-billing/ChangePaymentMethod.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Trans, t } from '@lingui/macro'
import { Button, FormControl, InputLabel, MenuItem, Select, Stack, Typography } from '@mui/material'
import { MutableRefObject, useId, useState } from 'react'
import { useUserProfile } from 'src/core/auth'
import { endPoints, env } from 'src/shared/constants'
import { LinkButton } from 'src/shared/link-button'
import { Modal } from 'src/shared/modal'
import { PaymentMethod, PaymentMethods, ProductTier } from 'src/shared/types/server'
import { paymentMethodToLabel, paymentMethods } from './utils'

export interface ChangePaymentNoMethodModalProps {
showModalRef: MutableRefObject<((show?: boolean | undefined) => void) | undefined>
selectedProductTier: ProductTier
defaultOpen?: boolean
onClose?: () => void
}

export const ChangePaymentNoMethodModal = ({
showModalRef,
defaultOpen,
selectedProductTier,
onClose,
}: ChangePaymentNoMethodModalProps) => {
const [paymentMethod, setPaymentMethod] = useState<PaymentMethod>({ method: 'stripe', subscription_id: '' })
const id = useId()
const { selectedWorkspace } = useUserProfile()

return (
<Modal
defaultOpen={defaultOpen}
openRef={showModalRef}
onClose={onClose}
actions={
<Stack direction="row" spacing={1} justifyContent={paymentMethod.method === 'none' ? 'end' : 'space-between'} width="100%" pt={1}>
<Button
variant="outlined"
onClick={() => {
onClose?.()
showModalRef.current?.(false)
}}
color="error"
>
Cancel
</Button>
{paymentMethod.method === 'none' ? null : (
<LinkButton
href={
paymentMethod.method === 'aws_marketplace'
? `${env.aws_marketplace_url}?product_tier=${selectedProductTier}`
: `${env.apiUrl}/${endPoints.workspaces.workspace(selectedWorkspace?.id ?? '').subscription.stripe}?product_tier=${selectedProductTier}`
}
endIcon={null}
loadingPosition="center"
disabled={paymentMethod.method === 'aws_marketplace' && !env.aws_marketplace_url}
variant="outlined"
color="primary"
>
{paymentMethod.method === 'aws_marketplace' ? (
<Trans>To AWS Marketplace</Trans>
) : (
<Trans>Add a New Credit or Debit Card</Trans>
)}
</LinkButton>
)}
</Stack>
}
title={t`Payment Method Required`}
description={<Trans>You need a payment method to change your product tier</Trans>}
>
<Typography py={2} fontWeight={600}>
<Trans>Please add a payment method to switch your workspace's product tier</Trans>
</Typography>
<FormControl fullWidth size="small">
<InputLabel id={`payment-method-to-add-${id}`}>
<Trans>Payment method to add</Trans>
</InputLabel>
<Select
labelId={`payment-method-to-add-${id}`}
value={paymentMethod.method}
label={<Trans>Payment method to add</Trans>}
onChange={({ target: { value } }) => setPaymentMethod({ method: value as PaymentMethods, subscription_id: '' })}
size="small"
>
{paymentMethods.map((paymentMethod) => (
<MenuItem key={paymentMethod} value={paymentMethod}>
{paymentMethodToLabel(paymentMethod)}
</MenuItem>
))}
</Select>
</FormControl>
</Modal>
)
}
177 changes: 177 additions & 0 deletions src/pages/panel/workspace-settings-billing/ChangeProductTier.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { Trans } from '@lingui/macro'
import CreditCardIcon from '@mui/icons-material/CreditCard'
import { ButtonBase, Divider, Stack, Typography, alpha } from '@mui/material'
import { Fragment, useRef, useState } from 'react'
import { AwsLogo } from 'src/assets/icons'
import { useUserProfile } from 'src/core/auth'
import { endPoints, env } from 'src/shared/constants'
import { LinkButton } from 'src/shared/link-button'
import { PaymentMethod, ProductTier } from 'src/shared/types/server'
import { ChangePaymentNoMethodModal } from './ChangePaymentNoMethodModal'
import { ChangeProductTierModal } from './ChangeProductTierModal'
import { ChangeProductTierToFreeModal } from './ChangeProductTierToFreeModal'
import { ProductTierComp } from './ProductTierComp'
import { ProductTierDivider } from './ProductTierDivider'
import { useGetProductTierFromSearchParams } from './utils'

interface ChangeProductTierProps {
selectedWorkspacePaymentMethod: PaymentMethod
workspacePaymentMethods: PaymentMethod[]
defaultProductTier: ProductTier
nextBillingCycle: Date
}

const allProductTiers: readonly ProductTier[] = ['Free', 'Plus', 'Business', 'Enterprise'] as const

export const ChangeProductTier = ({
defaultProductTier,
selectedWorkspacePaymentMethod,
workspacePaymentMethods,
nextBillingCycle,
}: ChangeProductTierProps) => {
const { selectedWorkspace } = useUserProfile()
const tierFromSearchParams = useGetProductTierFromSearchParams()
const showModalRef = useRef<(show?: boolean | undefined) => void>()
const showNoMethodModalRef = useRef<(show?: boolean | undefined) => void>()

const [awsMarketPlacePaymentMethod, stripePaymentMethod] = [
selectedWorkspacePaymentMethod.method === 'aws_marketplace' ? selectedWorkspacePaymentMethod : undefined,
selectedWorkspacePaymentMethod.method === 'stripe' ? selectedWorkspacePaymentMethod : undefined,
]

const noWorkspaceMethod = selectedWorkspacePaymentMethod.method === 'none'

const [productTier, setProductTier] = useState<ProductTier>(() =>
noWorkspaceMethod ? defaultProductTier : tierFromSearchParams ?? defaultProductTier,
)

const isUpgrade =
productTier === defaultProductTier || (defaultProductTier === 'Trial' && productTier === 'Free')
? null
: allProductTiers.indexOf(productTier) > allProductTiers.indexOf(defaultProductTier)

return (
<>
<Stack direction={{ xs: 'column', sm: 'row' }} flexWrap="wrap" alignItems={{ xs: 'center', sm: 'stretch' }} justifyContent="center">
{allProductTiers.map((curProductTier, i) => {
const selectedProductTier = curProductTier === productTier || (productTier === 'Trial' && curProductTier === 'Free')
return (
<Fragment key={curProductTier}>
{i ? <ProductTierDivider /> : null}
{selectedProductTier ? (
<Stack
sx={{
alignItems: 'baseline',
textAlign: 'left',
justifyContent: 'stretch',
px: { xs: 2, lg: 4 },
py: { xs: 2, lg: 4 },
bgcolor: ({
palette: {
primary: { main },
},
}) => alpha(main, 0.15),
borderRadius: 2,
boxShadow: 12,
transition: (theme) => theme.transitions.create(['box-shadow', 'background-color']),
}}
>
<ProductTierComp productTier={curProductTier} />
</Stack>
) : (
<ButtonBase
LinkComponent={Stack}
sx={{
alignItems: 'baseline',
textAlign: 'left',
justifyContent: 'stretch',
px: { xs: 2, lg: 4 },
py: { xs: 2, lg: 4 },
borderRadius: 2,
transition: (theme) => theme.transitions.create(['box-shadow', 'background-color']),
}}
onClick={() => setProductTier(curProductTier)}
>
<ProductTierComp productTier={curProductTier} />
</ButtonBase>
)}
</Fragment>
)
})}
</Stack>
{isUpgrade !== null ? (
productTier === 'Free' ? (
<ChangeProductTierToFreeModal
onClose={() => setProductTier(defaultProductTier)}
productTier={defaultProductTier}
showModalRef={showModalRef}
defaultOpen={true}
/>
) : noWorkspaceMethod ? (
<ChangePaymentNoMethodModal
selectedProductTier={productTier}
showModalRef={showNoMethodModalRef}
defaultOpen={true}
onClose={() => setProductTier(defaultProductTier)}
/>
) : (
<ChangeProductTierModal
workspacePaymentMethods={workspacePaymentMethods}
nextBillingCycle={nextBillingCycle}
onClose={() => setProductTier(defaultProductTier)}
isUpgrade={isUpgrade}
productTier={defaultProductTier}
selectedProductTier={productTier}
selectedWorkspacePaymentMethod={selectedWorkspacePaymentMethod}
showModalRef={showModalRef}
defaultOpen={true}
/>
)
) : (
<Stack alignItems="center" spacing={2} pt={4}>
{noWorkspaceMethod ? null : (
<>
<Stack py={1} spacing={1} alignItems="center">
{awsMarketPlacePaymentMethod ? (
<Stack direction="row" spacing={1} alignItems="center">
<LinkButton
startIcon={<AwsLogo height={50} />}
endIcon={null}
loadingPosition="start"
variant="outlined"
href={`${env.aws_marketplace_url}`}
>
<Typography textTransform="none">
<Trans>Manage AWS Market place payment method</Trans>
</Typography>
</LinkButton>
</Stack>
) : null}
{stripePaymentMethod ? (
<Stack direction="row" spacing={1} alignItems="center">
<LinkButton
startIcon={<CreditCardIcon fontSize="large" sx={{ fontSize: '48px!important' }} />}
endIcon={null}
loadingPosition="start"
sx={{
maxWidth: '100%',
width: 580,
}}
variant="outlined"
href={`${env.apiUrl}/${endPoints.workspaces.workspace(selectedWorkspace?.id ?? '').subscription.stripe}`}
>
<Typography textTransform="none">
<Trans>Manage Card Details</Trans>
</Typography>
</LinkButton>
</Stack>
) : null}
</Stack>
</>
)}
</Stack>
)}
<Divider />
</>
)
}
Loading

0 comments on commit 18ab690

Please sign in to comment.