Skip to content

Commit

Permalink
chore: Migrate useSelfHostedSeatsConfig to TS Query V5 (#3580)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholas-codecov authored Dec 27, 2024
1 parent c87e433 commit 0e34c4d
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 189 deletions.
44 changes: 27 additions & 17 deletions src/layouts/Header/components/SeatDetails/SeatDetails.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import {
QueryClientProvider as QueryClientProviderV5,
QueryClient as QueryClientV5,
} from '@tanstack/react-queryV5'
import { render, screen } from '@testing-library/react'
import { graphql, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { Suspense } from 'react'
import { MemoryRouter, Route } from 'react-router-dom'

import SeatDetails from './SeatDetails'
Expand All @@ -14,37 +19,43 @@ const mockData = {
}

const mockUndefinedSeats = {
config: {},
config: null,
}

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

const wrapper: ({
initialEntries,
}: {
initialEntries?: string
}) => React.FC<React.PropsWithChildren> =
({ initialEntries = '/gh' }) =>
({ children }) => (
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={[initialEntries]}>
<Route path="/:provider" exact>
{children}
</Route>
</MemoryRouter>
</QueryClientProvider>
<QueryClientProviderV5 client={queryClientV5}>
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={[initialEntries]}>
<Route path="/:provider" exact>
<Suspense fallback={<div>Loading</div>}>{children}</Suspense>
</Route>
</MemoryRouter>
</QueryClientProvider>
</QueryClientProviderV5>
)

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

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

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

afterAll(() => {
Expand All @@ -62,12 +73,10 @@ describe('SeatDetails', () => {

describe('renders component', () => {
describe('values are defined', () => {
beforeEach(() => {
setup({})
})

it('displays the number of active seats', async () => {
setup({})
render(<SeatDetails />, { wrapper: wrapper({}) })

const number = await screen.findByText('5')
expect(number).toBeInTheDocument()

Expand All @@ -76,6 +85,7 @@ describe('SeatDetails', () => {
})

it('displays the number of total seats', async () => {
setup({})
render(<SeatDetails />, { wrapper: wrapper({}) })

const number = await screen.findByText('10')
Expand Down
14 changes: 12 additions & 2 deletions src/layouts/Header/components/SeatDetails/SeatDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { useSelfHostedSeatsConfig } from 'services/selfHosted'
import { useSuspenseQuery as useSuspenseQueryV5 } from '@tanstack/react-queryV5'
import { useParams } from 'react-router'

import { SelfHostedSeatsConfigQueryOpts } from 'services/selfHosted/SelfHostedSeatsConfigQueryOpts'

interface URLParams {
provider: string
}

function SeatDetails() {
const { data: selfHostedSeats } = useSelfHostedSeatsConfig()
const { provider } = useParams<URLParams>()
const { data: selfHostedSeats } = useSuspenseQueryV5(
SelfHostedSeatsConfigQueryOpts({ provider })
)

if (!selfHostedSeats?.seatsUsed || !selfHostedSeats?.seatsLimit) {
return <p>Unable to get seat usage information</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useQueryClient } from '@tanstack/react-query'
import { useSuspenseQuery as useSuspenseQueryV5 } from '@tanstack/react-queryV5'
import { useParams } from 'react-router'

import {
useSelfHostedCurrentUser,
useSelfHostedSeatsConfig,
} from 'services/selfHosted'
import { useSelfHostedCurrentUser } from 'services/selfHosted'
import { SelfHostedSeatsConfigQueryOpts } from 'services/selfHosted/SelfHostedSeatsConfigQueryOpts'
import A from 'ui/A'
import Banner from 'ui/Banner'
import BannerContent from 'ui/Banner/BannerContent'
Expand Down Expand Up @@ -39,9 +39,12 @@ function canChangeActivation({ seatConfig, currentUser }) {
}

function ActivationBanner() {
const { provider } = useParams()
const queryClient = useQueryClient()
const { data: currentUser } = useSelfHostedCurrentUser()
const { data: seatConfig } = useSelfHostedSeatsConfig()
const { data: seatConfig } = useSuspenseQueryV5(
SelfHostedSeatsConfigQueryOpts({ provider })
)

const { canChange, displaySeatMsg } = canChangeActivation({
seatConfig,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import {
QueryClientProvider as QueryClientProviderV5,
QueryClient as QueryClientV5,
} from '@tanstack/react-queryV5'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { graphql, http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { Route } from 'react-router-dom'
import { MemoryRouter } from 'react-router-dom/cjs/react-router-dom.min'
import { Suspense } from 'react'
import { MemoryRouter, Route } from 'react-router-dom'

import ActivationBanner from './ActivationBanner'

Expand All @@ -27,27 +31,38 @@ const mockUserData = {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
})
const server = setupServer()

const queryClientV5 = new QueryClientV5({
defaultOptions: { queries: { retry: false } },
})

const wrapper = ({ children }) => (
<QueryClientProviderV5 client={queryClientV5}>
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={['/gh']}>
<Route path="/:provider">
<Suspense fallback={<div>Loading</div>}>{children}</Suspense>
</Route>
</MemoryRouter>
</QueryClientProvider>
</QueryClientProviderV5>
)

const server = setupServer()
beforeAll(() => {
server.listen()
})
beforeEach(() => {

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

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

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

describe('ActivationBanner', () => {
function setup(
{ overrideUserData = {}, overrideSeatData = {} } = {
Expand All @@ -58,14 +73,14 @@ describe('ActivationBanner', () => {
const user = userEvent.setup()

let restUsersCurrent = { ...mockUserData, ...overrideUserData }
const querySeats = { ...mockSeatData, ...overrideSeatData }
const querySeats = { ...mockSeatData.config, ...overrideSeatData }

server.use(
http.get('/internal/users/current', () => {
return HttpResponse.json(restUsersCurrent)
}),
graphql.query('Seats', () => {
return HttpResponse.json({ data: querySeats })
return HttpResponse.json({ data: { config: querySeats } })
}),
http.patch('/internal/users/current', async (info) => {
const { activated } = await info.request.json()
Expand All @@ -83,9 +98,8 @@ describe('ActivationBanner', () => {
}

describe('rendering banner header', () => {
beforeEach(() => setup())

it('renders header content', async () => {
setup()
render(<ActivationBanner />, { wrapper })

const heading = await screen.findByText('Activation Status')
Expand All @@ -95,9 +109,8 @@ describe('ActivationBanner', () => {

describe('rendering banner content', () => {
describe('user is activated', () => {
beforeEach(() => setup({ overrideUserData: { activated: true } }))

it('displays user is activated', async () => {
setup({ overrideUserData: { activated: true } })
render(<ActivationBanner />, { wrapper })

const activated = await screen.findByText('You are currently activated')
Expand All @@ -107,9 +120,8 @@ describe('ActivationBanner', () => {

describe('user is not activated', () => {
describe('org has free seats', () => {
beforeEach(() => setup({ overrideSeatData: { activated: false } }))

it('displays user is not activated', async () => {
setup({ overrideSeatData: { activated: false } })
render(<ActivationBanner />, { wrapper })

const activated = await screen.findByText(
Expand All @@ -120,14 +132,11 @@ describe('ActivationBanner', () => {
})

describe('org does not have free seats', () => {
beforeEach(() =>
it('displays org out of seat message', async () => {
setup({
overrideSeatData: { seatsUsed: 10, seatsLimit: 10 },
overrideUserData: { activated: false },
})
)

it('displays org out of seat message', async () => {
render(<ActivationBanner />, { wrapper })

const noSeatMsg = await screen.findByText(
Expand All @@ -137,6 +146,10 @@ describe('ActivationBanner', () => {
})

it('sets toggle to disabled', async () => {
setup({
overrideSeatData: { seatsUsed: 10, seatsLimit: 10 },
overrideUserData: { activated: false },
})
render(<ActivationBanner />, { wrapper })

const button = await screen.findByRole('button')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useMutation } from '@tanstack/react-query'
import { useQueryClient as useQueryClientV5 } from '@tanstack/react-queryV5'
import { useParams } from 'react-router-dom'

import { SelfHostedSeatsConfigQueryOpts } from 'services/selfHosted/SelfHostedSeatsConfigQueryOpts'
import Api from 'shared/api'

export const useSelfActivationMutation = ({ queryClient, canChange }) => {
const { provider } = useParams()
const queryClientV5 = useQueryClientV5()

return useMutation({
mutationFn: (activated) => {
Expand All @@ -18,43 +21,51 @@ export const useSelfActivationMutation = ({ queryClient, canChange }) => {
},
onMutate: async (activated) => {
await queryClient.cancelQueries(['SelfHostedCurrentUser'])
await queryClient.cancelQueries(['Seats'])
await queryClientV5.cancelQueries({
queryKey: SelfHostedSeatsConfigQueryOpts({ provider }).queryKey,
})

const prevUser = queryClient.getQueryData(['SelfHostedCurrentUser'])
const prevSeat = queryClient.getQueryData(['Seats'])
const prevSeat = queryClientV5.getQueryData(
SelfHostedSeatsConfigQueryOpts({ provider }).queryKey
)

if (canChange) {
queryClient.setQueryData(['SelfHostedCurrentUser'], (user) => ({
...user,
activated,
}))

queryClient.setQueryData(['Seats'], (seats) => {
const seatsUsed = seats?.data?.config?.seatsUsed

return {
data: {
config: {
...seats?.data?.config,
seatsUsed: activated ? seatsUsed + 1 : seatsUsed - 1,
queryClientV5.setQueryData(
SelfHostedSeatsConfigQueryOpts({ provider }).queryKey,
(seats) => {
const seatsUsed = seats?.data?.config?.seatsUsed
return {
data: {
config: {
...seats?.data?.config,
seatsUsed: activated ? seatsUsed + 1 : seatsUsed - 1,
},
},
},
}
}
})
)
}

return {
prevUser,
prevSeat,
}
return { prevUser, prevSeat }
},
onError: (_err, _activated, context) => {
queryClient.setQueryData(['SelfHostedCurrentUser'], context.prevUser)
queryClient.setQueryData(['Seats'], context.prevSeat)
queryClientV5.setQueryData(
SelfHostedSeatsConfigQueryOpts({ provider }).queryKey,
context.prevSeat
)
},
onSettled: () => {
queryClient.invalidateQueries(['SelfHostedCurrentUser'])
queryClient.invalidateQueries(['Seats'])
queryClientV5.invalidateQueries(
SelfHostedSeatsConfigQueryOpts({ provider }).queryKey
)
},
})
}
Loading

0 comments on commit 0e34c4d

Please sign in to comment.