Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
"@types/js-cookie": "3.0.6",
"@types/lodash": "4.17.6",
"@types/node": "^22.9.0",
"@types/pluralize": "^0.0.33",
"@types/prismjs": "^1.26.4",
"@types/prop-types": "15.7.12",
"@types/qs": "6.9.15",
Expand Down
1 change: 1 addition & 0 deletions src/pages/AccountSettings/AccountSettings.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const mockPlanData = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
freeSeatCount: 0,
hasSeatsLeft: true,
}

Expand Down
1 change: 1 addition & 0 deletions src/pages/AccountSettings/AccountSettingsSideMenu.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const mockPlanData = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
freeSeatCount: 0,
hasSeatsLeft: true,
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pluralize from 'pluralize'
import { useParams } from 'react-router-dom'

import { useAccountDetails } from 'services/account/useAccountDetails'
Expand Down Expand Up @@ -74,6 +75,9 @@ function Activation() {
activated members of{' '}
<span className="text-lg font-semibold">{planQuantity}</span> available
seats{' '}
{planData?.plan?.freeSeatCount
? `(${planData?.plan?.freeSeatCount} free ${pluralize('seat', planData?.plan?.freeSeatCount)} included) `
: ''}
{accountDetails && (
<ChangePlanLink
accountDetails={accountDetails}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const mockPlanData = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 9,
freeSeatCount: 2,
hasSeatsLeft: true,
}

Expand Down Expand Up @@ -140,6 +141,15 @@ describe('Activation', () => {
expect(availableSeats).toBeInTheDocument()
})

it('displays number of plan free seats', async () => {
setup()

render(<Activation />, { wrapper: wrapper() })

const freeSeats = await screen.findByText(/2 free seats included/)
expect(freeSeats).toBeInTheDocument()
})

it('displays change plan link', async () => {
setup()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const mockPlanData = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
freeSeatCount: 1,
hasSeatsLeft: true,
isEnterprisePlan: false,
isFreePlan: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ const mockPlanData = {
trialEndDate: '',
trialTotalDays: 0,
pretrialUsersCount: 0,
freeSeatCount: 0,
}

const server = setupServer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const mockPlanDataResponse = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
freeSeatCount: 0,
hasSeatsLeft: true,
isEnterprisePlan: false,
isFreePlan: false,
Expand Down
1 change: 1 addition & 0 deletions src/pages/OwnerPage/HeaderBanners/HeaderBanners.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const mockPlanDataResponse = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
freeSeatCount: 0,
hasSeatsLeft: true,
isEnterprisePlan: false,
isFreePlan: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const mockPlanDataResponse = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
freeSeatCount: 0,
hasSeatsLeft: true,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const mockResponse = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
freeSeatCount: 0,
hasSeatsLeft: true,
isEnterprisePlan: false,
isSentryPlan: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ vi.mock('./subRoutes/TeamPlanSpecialOffer', () => ({
const teamPlans = [
{
baseUnitPrice: 6,
benefits: ['Up to 10 users'],
benefits: ['Up to 10 paid users'],
billingRate: BillingRate.MONTHLY,
marketingName: 'Users Team',
monthlyUploadLimit: 2500,
Expand All @@ -29,7 +29,7 @@ const teamPlans = [
},
{
baseUnitPrice: 5,
benefits: ['Up to 10 users'],
benefits: ['Up to 10 paid users'],
billingRate: BillingRate.ANNUALLY,
marketingName: 'Users Team',
monthlyUploadLimit: 2500,
Expand Down Expand Up @@ -85,6 +85,7 @@ const mockPlanData = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
freeSeatCount: 0,
hasSeatsLeft: true,
isEnterprisePlan: false,
isFreePlan: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const mockPlanData = {
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 5,
freeSeatCount: 0,
hasSeatsLeft: false,
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const mockAvailablePlans = [
},
{
baseUnitPrice: 6,
benefits: ['Up to 10 users'],
benefits: ['Up to 10 paid users'],
billingRate: BillingRate.MONTHLY,
marketingName: 'Users Team',
monthlyUploadLimit: 2500,
Expand All @@ -97,7 +97,7 @@ const mockAvailablePlans = [
},
{
baseUnitPrice: 5,
benefits: ['Up to 10 users'],
benefits: ['Up to 10 paid users'],
billingRate: BillingRate.ANNUALLY,
marketingName: 'Users Team',
monthlyUploadLimit: 2500,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ interface URLParams {
owner: string
}

export const MONTHS_PER_YEAR = 12

function BillingDetails() {
const { provider, owner } = useParams<URLParams>()
const { data: accountDetails } = useAccountDetails({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const cardBrand = {
},
}

function CardInformation({ subscriptionDetail, card }) {
function CardInformation({ subscriptionDetail, card, nextBillPrice }) {
const typeCard = cardBrand[card?.brand] ?? cardBrand?.fallback
let nextBilling = null

Expand Down Expand Up @@ -61,7 +61,11 @@ function CardInformation({ subscriptionDetail, card }) {
{nextBilling && (
<p className="text-sm text-ds-gray-quinary">
Your next billing date is{' '}
<span className="text-ds-gray-octonary">{nextBilling}</span>.
<span className="text-ds-gray-octonary">
{nextBilling}
{nextBillPrice ? ` for ${nextBillPrice}` : ''}
</span>
.
</p>
)}
</div>
Expand All @@ -76,6 +80,7 @@ CardInformation.propTypes = {
expMonth: PropTypes.number.isRequired,
expYear: PropTypes.number.isRequired,
}).isRequired,
nextBillPrice: PropTypes.string,
}

export default CardInformation
Original file line number Diff line number Diff line change
@@ -1,27 +1,80 @@
import PropTypes from 'prop-types'
import { useState } from 'react'
import { useMemo, useState } from 'react'

import { accountDetailsPropType } from 'services/account/propTypes'
import { formatTimestampToCalendarDate } from 'shared/utils/billing'
import { usePlanData } from 'services/account/usePlanData'
import {
BillingRate,
formatNumberToUSD,
formatTimestampToCalendarDate,
} from 'shared/utils/billing'
import {
calculatePriceProPlan,
calculatePriceSentryPlan,
calculatePriceTeamPlan,
} from 'shared/utils/upgradeForm'
import A from 'ui/A'
import Button from 'ui/Button'
import Icon from 'ui/Icon'

import BankInformation from './BankInformation'
import CardInformation from './CardInformation'
import PaymentMethodForm from './PaymentMethodForm'

import { MONTHS_PER_YEAR } from '../BillingDetails'
function PaymentCard({ accountDetails, provider, owner }) {
const [isFormOpen, setIsFormOpen] = useState(false)
const { data: planData } = usePlanData({
provider,
owner,
})
const subscriptionDetail = accountDetails?.subscriptionDetail
const card = subscriptionDetail?.defaultPaymentMethod?.card
const usBankAccount = subscriptionDetail?.defaultPaymentMethod?.usBankAccount

let nextBillingDisplayDate = null
if (!subscriptionDetail?.cancelAtPeriodEnd) {
nextBillingDisplayDate = formatTimestampToCalendarDate(
subscriptionDetail?.currentPeriodEnd
)
}
const scheduledPhaseQuantity =
accountDetails?.scheduleDetail?.scheduledPhase?.quantity

const nextBillPrice = useMemo(() => {
const isPerYear = planData?.plan?.billingRate === BillingRate.ANNUALLY
let seats =
scheduledPhaseQuantity ??
(planData?.plan?.planUserCount ?? 0) -
(planData?.plan?.freeSeatCount ?? 0)
seats = Math.max(seats, 0)
const planBaseUnitPrice = planData?.plan?.baseUnitPrice ?? 0
const billPrice = planData?.plan?.isProPlan
? calculatePriceProPlan({
seats,
baseUnitPrice: planBaseUnitPrice,
})
: planData?.plan?.isTeamPlan
? calculatePriceTeamPlan({
seats,
baseUnitPrice: planBaseUnitPrice,
})
: calculatePriceSentryPlan({
seats,
baseUnitPrice: planBaseUnitPrice,
})

return formatNumberToUSD(
isPerYear ? billPrice * MONTHS_PER_YEAR : billPrice
)
}, [
planData?.plan?.billingRate,
planData?.plan?.baseUnitPrice,
planData?.plan?.planUserCount,
planData?.plan?.freeSeatCount,
planData?.plan?.isProPlan,
planData?.plan?.isTeamPlan,
scheduledPhaseQuantity,
])

return (
<div className="flex flex-col gap-3 border-t p-4">
Expand All @@ -45,7 +98,11 @@ function PaymentCard({ accountDetails, provider, owner }) {
accountDetails={accountDetails}
/>
) : card ? (
<CardInformation card={card} subscriptionDetail={subscriptionDetail} />
<CardInformation
card={card}
subscriptionDetail={subscriptionDetail}
nextBillPrice={nextBillPrice}
/>
) : usBankAccount ? (
<BankInformation
usBankAccount={usBankAccount}
Expand Down
Loading