Skip to content

Commit

Permalink
Merge branch 'main' into team-repos-list
Browse files Browse the repository at this point in the history
  • Loading branch information
RulaKhaled committed Nov 3, 2023
2 parents 61d685a + f507526 commit eefd552
Show file tree
Hide file tree
Showing 10 changed files with 374 additions and 132 deletions.
Original file line number Diff line number Diff line change
@@ -1,33 +1,46 @@
import { useParams } from 'react-router-dom'

import { usePlanData } from 'services/account'
import A from 'ui/A'
import Banner from 'ui/Banner'
import BannerContent from 'ui/Banner/BannerContent'
import BannerHeading from 'ui/Banner/BannerHeading'
import Button from 'ui/Button'

const ExceededUploadsAlert = () => (
<Banner>
<BannerHeading>
<h2 className="font-semibold">Upload limit has been reached</h2>
</BannerHeading>
<BannerContent>
<p>
This org is currently on the free plan; which includes 250 free uploads
monthly. This month&apos;s period has been reached and the reports will
not generate. To resolve this,{' '}
<A to={{ pageName: 'upgradeOrgPlan' }}>upgrade plan</A> and you&apos;ll
have unlimited uploads.
</p>
<div className="my-6 w-36">
<Button to={{ pageName: 'upgradeOrgPlan' }} variant="primary">
Upgrade plan
</Button>
</div>
<p>
<span className="font-semibold">Need help?</span> Connect with our sales
team today at <A to={{ pageName: 'sales' }}>sales@codecov.io</A>
</p>
</BannerContent>
</Banner>
)
const ExceededUploadsAlert = () => {
const { owner, provider } = useParams()
const { data: planData } = usePlanData({
provider,
owner,
})

const planName = planData?.plan.marketingName
const monthlyUploadLimit = planData?.plan.monthlyUploadLimit
return (
<Banner>
<BannerHeading>
<h2 className="font-semibold">Upload limit has been reached</h2>
</BannerHeading>
<BannerContent>
<p>
This org is currently on the {planName} plan; which includes{' '}
{monthlyUploadLimit} free uploads monthly. This month&apos;s limit has
been reached and the reports will not generate. To resolve this,{' '}
<A to={{ pageName: 'upgradeOrgPlan' }}>upgrade plan</A> and
you&apos;ll have unlimited uploads.
</p>
<div className="my-6 w-36">
<Button to={{ pageName: 'upgradeOrgPlan' }} variant="primary">
Upgrade plan
</Button>
</div>
<p>
<span className="font-semibold">Need help?</span> Connect with our
sales team today at <A to={{ pageName: 'sales' }}>sales@codecov.io</A>
</p>
</BannerContent>
</Banner>
)
}

export default ExceededUploadsAlert
Original file line number Diff line number Diff line change
@@ -1,41 +1,111 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen } from '@testing-library/react'
import { graphql } from 'msw'
import { setupServer } from 'msw/node'
import { MemoryRouter, Route } from 'react-router-dom'

import { TrialStatuses } from 'services/account'

import ExceededUploadsAlert from './ExceededUploadsAlert'

const server = setupServer()

const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
})

const wrapper = ({ children }) => (
<MemoryRouter initialEntries={['/gh/codecov']}>
<Route path="/:provider/:owner">{children}</Route>
</MemoryRouter>
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={['/gh/codecov']}>
<Route path="/:provider/:owner">{children}</Route>
</MemoryRouter>
</QueryClientProvider>
)

const mockPlanDataResponse = {
baseUnitPrice: 10,
benefits: [],
billingRate: 'monthly',
marketingName: 'some-name',
monthlyUploadLimit: 123,
value: 'test-plan',
trialStatus: TrialStatuses.NOT_STARTED,
trialStartDate: '',
trialEndDate: '',
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
}

beforeAll(() => {
server.listen()
})

afterEach(() => {
queryClient.clear()
server.resetHandlers()
})

afterAll(() => {
server.close()
})

describe('ExceededUploadsAlert', () => {
function setup() {
server.use(
graphql.query('GetPlanData', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.data({
owner: {
plan: {
...mockPlanDataResponse,
},
},
})
)
})
)
}
describe('rendering banner', () => {
beforeEach(() => {
setup()
})

it('has header content', () => {
render(<ExceededUploadsAlert />, { wrapper })

const heading = screen.getByText('Upload limit has been reached')
expect(heading).toBeInTheDocument()
})

it('has body content', () => {
render(<ExceededUploadsAlert />, { wrapper })

const body = screen.getByText(/This org is currently/)
expect(body).toBeInTheDocument()
})

it('has links to upgrade org plan', () => {
it('has the correct plan name', async () => {
render(<ExceededUploadsAlert />, { wrapper })
const body = await screen.findByText(/some-name/)
expect(body).toBeInTheDocument()
})

it('has the correct upload limit', async () => {
render(<ExceededUploadsAlert />, { wrapper })

const body = await screen.findByText(/includes 123 free uploads/)
expect(body).toBeInTheDocument()
})

it('has links to upgrade org plan', () => {
render(<ExceededUploadsAlert />, { wrapper })
const links = screen.getAllByRole('link', { name: /upgrade plan/i })
expect(links.length).toBe(2)
expect(links[0]).toHaveAttribute('href', '/plan/gh/codecov/upgrade')
})

it('has link to email sales team', () => {
render(<ExceededUploadsAlert />, { wrapper })

const link = screen.getByRole('link', { name: /sales@codecov.io/ })
expect(link).toBeInTheDocument()
expect(link).toHaveAttribute('href', 'https://about.codecov.io/sales')
Expand Down
50 changes: 28 additions & 22 deletions src/pages/OwnerPage/Header/HeaderBanners/HeaderBanners.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,53 @@ import { useParams } from 'react-router-dom'
import config from 'config'

import { useOwnerPageData } from 'pages/OwnerPage/hooks'
import { useAccountDetails } from 'services/account'
import { useAccountDetails, usePlanData } from 'services/account'

import ExceededUploadsAlert from './ExceededUploadsAlert'
import GithubConfigBanner from './GithubConfigBanner'
import ReachingUploadLimit from './ReachingUploadLimit'

const MAX_UPLOADS_NUMBER = 250
const REACHING_UPLOAD_LIMIT = 225
import ReachingUploadLimitAlert from './ReachingUploadLimitAlert'

const useUploadsInfo = () => {
const { owner } = useParams()
const { owner, provider } = useParams()
const { data: ownerData } = useOwnerPageData({ username: owner })
const numberOfUploads = ownerData?.numberOfUploads
const { data: planData } = usePlanData({
provider,
owner,
})

const isUploadsExceeded = numberOfUploads >= MAX_UPLOADS_NUMBER
const isUploadsReachingLimit =
numberOfUploads < MAX_UPLOADS_NUMBER &&
numberOfUploads >= REACHING_UPLOAD_LIMIT

return { isUploadsExceeded, isUploadsReachingLimit }
// If monthlyUploadLimit is not defined, we consider the account can have an
// unlimited amount of uploads
const monthlyUploadLimit = planData?.plan?.monthlyUploadLimit
const isUploadLimitExceeded = monthlyUploadLimit
? numberOfUploads >= monthlyUploadLimit
: false
const isApproachingUploadLimit = monthlyUploadLimit
? !isUploadLimitExceeded && numberOfUploads >= 0.9 * monthlyUploadLimit
: false
return { isUploadLimitExceeded, isApproachingUploadLimit }
}

const AlertBanners = ({
isUploadsExceeded,
isUploadsReachingLimit,
isUploadLimitExceeded,
isApproachingUploadLimit,
hasGhApp,
}) => {
return (
<>
{!hasGhApp && <GithubConfigBanner />}
{isUploadsExceeded ? (
{isUploadLimitExceeded ? (
<ExceededUploadsAlert />
) : isUploadsReachingLimit ? (
<ReachingUploadLimit />
) : isApproachingUploadLimit ? (
<ReachingUploadLimitAlert />
) : null}
</>
)
}

AlertBanners.propTypes = {
isUploadsExceeded: PropTypes.bool.isRequired,
isUploadsReachingLimit: PropTypes.bool.isRequired,
isUploadLimitExceeded: PropTypes.bool.isRequired,
isApproachingUploadLimit: PropTypes.bool.isRequired,
hasGhApp: PropTypes.bool.isRequired,
}

Expand All @@ -56,7 +61,8 @@ export default function HeaderBanners() {
provider,
owner,
})
const { isUploadsExceeded, isUploadsReachingLimit } = useUploadsInfo()

const { isUploadLimitExceeded, isApproachingUploadLimit } = useUploadsInfo()

const hasGhApp = !!accountDetails?.integrationId

Expand All @@ -67,8 +73,8 @@ export default function HeaderBanners() {
return (
<>
<AlertBanners
isUploadsExceeded={isUploadsExceeded}
isUploadsReachingLimit={isUploadsReachingLimit}
isUploadLimitExceeded={isUploadLimitExceeded}
isApproachingUploadLimit={isApproachingUploadLimit}
hasGhApp={hasGhApp}
/>
</>
Expand Down
65 changes: 65 additions & 0 deletions src/pages/OwnerPage/Header/HeaderBanners/HeaderBanners.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { MemoryRouter, Route } from 'react-router-dom'

import config from 'config'

import { TrialStatuses } from 'services/account'

import HeaderBanners from './HeaderBanners'

jest.mock('config')
Expand All @@ -23,6 +25,26 @@ const wrapper = ({ children }) => (
</QueryClientProvider>
)

const mockPlanDataResponse = {
baseUnitPrice: 10,
benefits: [],
billingRate: 'monthly',
marketingName: 'Pro Team',
monthlyUploadLimit: 250,
value: 'test-plan',
trialStatus: TrialStatuses.NOT_STARTED,
trialStartDate: '',
trialEndDate: '',
trialTotalDays: 0,
pretrialUsersCount: 0,
planUserCount: 1,
}

const mockPlanDataResponseNoUploadLimit = {
...mockPlanDataResponse,
monthlyUploadLimit: null,
}

beforeAll(() => {
server.listen()
})
Expand Down Expand Up @@ -68,6 +90,16 @@ describe('HeaderBanners', () => {

return res(ctx.status(200), ctx.data({}))
}),
graphql.query('GetPlanData', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.data({
owner: {
plan: mockPlanDataResponse,
},
})
)
}),
rest.get('/internal/gh/codecov/account-details/', (req, res, ctx) =>
res(ctx.status(200), ctx.json({ integrationId }))
)
Expand Down Expand Up @@ -162,6 +194,39 @@ describe('HeaderBanners', () => {
})
})

describe('org has no monthlyUploadLimit defined', () => {
beforeEach(() => {
setup({
hasReachedLimit: true,
})
server.use(
graphql.query('GetPlanData', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.data({
owner: {
plan: mockPlanDataResponseNoUploadLimit,
},
})
)
})
)
})

it('treats monthly uploads as unlimited', () => {
render(
<HeaderBanners
provider="gh"
owner={{ username: 'codecov', isCurrentUserPartOfOrg: true }}
/>,
{ wrapper }
)

const banner = screen.queryByText('Upload limit')
expect(banner).not.toBeInTheDocument()
})
})

describe('user does not have gh app installed', () => {
beforeEach(() => {
setup({
Expand Down
Loading

0 comments on commit eefd552

Please sign in to comment.