Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Migrate useSelfHostedCurrentUser to TS Query V5 #3582

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
30 changes: 17 additions & 13 deletions src/layouts/Header/components/AdminLink/AdminLink.test.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,43 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen } from '@testing-library/react'
import {
QueryClientProvider as QueryClientProviderV5,
QueryClient as QueryClientV5,
} from '@tanstack/react-queryV5'
import { render, screen, waitFor } from '@testing-library/react'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { Suspense } from 'react'
import { MemoryRouter, Route } from 'react-router-dom'

import AdminLink from './AdminLink'

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

const wrapper: ({
initialEntries,
}: {
initialEntries?: string
}) => React.FC<React.PropsWithChildren> =
({ initialEntries = '/gh' }) =>
({ children }) => (
<QueryClientProvider client={queryClient}>
<QueryClientProviderV5 client={queryClientV5}>
<MemoryRouter initialEntries={[initialEntries]}>
<Route path="/:provider" exact>
{children}
<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()
})

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

afterAll(() => {
Expand Down Expand Up @@ -69,7 +73,7 @@ describe('AdminLink', () => {
})

describe('user is not an admin', () => {
it('renders nothing', () => {
it('renders nothing', async () => {
setup({
activated: false,
email: '[email protected]',
Expand All @@ -80,7 +84,7 @@ describe('AdminLink', () => {
})

const { container } = render(<AdminLink />, { wrapper: wrapper({}) })
expect(container).toBeEmptyDOMElement()
await waitFor(() => expect(container).toBeEmptyDOMElement())
})
})
})
14 changes: 12 additions & 2 deletions src/layouts/Header/components/AdminLink/AdminLink.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { useSelfHostedCurrentUser } from 'services/selfHosted'
import { useSuspenseQuery as useSuspenseQueryV5 } from '@tanstack/react-queryV5'
import { useParams } from 'react-router'

import { SelfHostedCurrentUserQueryOpts } from 'services/selfHosted/SelfHostedCurrentUserQueryOpts'
import A from 'ui/A'
import Icon from 'ui/Icon'

interface URLParams {
provider: string
}

function AdminLink() {
const { data: user } = useSelfHostedCurrentUser()
const { provider } = useParams<URLParams>()
const { data: user } = useSuspenseQueryV5(
SelfHostedCurrentUserQueryOpts({ provider })
)

if (!user?.isAdmin) {
return null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useQueryClient } from '@tanstack/react-query'
import { useSuspenseQuery as useSuspenseQueryV5 } from '@tanstack/react-queryV5'
import { useParams } from 'react-router'

import { useSelfHostedCurrentUser } from 'services/selfHosted'
import { SelfHostedCurrentUserQueryOpts } from 'services/selfHosted/SelfHostedCurrentUserQueryOpts'
import { SelfHostedSeatsConfigQueryOpts } from 'services/selfHosted/SelfHostedSeatsConfigQueryOpts'
import A from 'ui/A'
import Banner from 'ui/Banner'
Expand Down Expand Up @@ -40,19 +39,20 @@ function canChangeActivation({ seatConfig, currentUser }) {

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

const { data: seatConfig } = useSuspenseQueryV5(
SelfHostedSeatsConfigQueryOpts({ provider })
)
const { data: currentUser } = useSuspenseQueryV5(
SelfHostedCurrentUserQueryOpts({ provider })
)

const { canChange, displaySeatMsg } = canChangeActivation({
seatConfig,
currentUser,
})

const { mutate } = useSelfActivationMutation({
queryClient,
canChange,
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { useMutation } from '@tanstack/react-query'
import { useQueryClient as useQueryClientV5 } from '@tanstack/react-queryV5'
import {
useMutation as useMutationV5,
useQueryClient as useQueryClientV5,
} from '@tanstack/react-queryV5'
import { useParams } from 'react-router-dom'

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

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

return useMutation({
return useMutationV5({
mutationFn: (activated) => {
if (canChange) {
return Api.patch({
Expand All @@ -20,49 +23,59 @@ export const useSelfActivationMutation = ({ queryClient, canChange }) => {
}
},
onMutate: async (activated) => {
await queryClient.cancelQueries(['SelfHostedCurrentUser'])
// Cancel any in-flight queries
await queryClientV5.cancelQueries({
queryKey: SelfHostedCurrentUserQueryOpts({ provider }).queryKey,
})
await queryClientV5.cancelQueries({
queryKey: SelfHostedSeatsConfigQueryOpts({ provider }).queryKey,
})

const prevUser = queryClient.getQueryData(['SelfHostedCurrentUser'])
// Get the current data before the mutation
const prevSeat = queryClientV5.getQueryData(
SelfHostedSeatsConfigQueryOpts({ provider }).queryKey
)
const prevUser = queryClientV5.getQueryData(
SelfHostedCurrentUserQueryOpts({ provider }).queryKey
)

if (canChange) {
queryClient.setQueryData(['SelfHostedCurrentUser'], (user) => ({
...user,
activated,
}))
// Optimistically update the data in the query client
queryClientV5.setQueryData(
SelfHostedCurrentUserQueryOpts({ provider }).queryKey,
(user) => ({ ...user, activated })
)

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

return { data: { config: { ...seats?.data?.config, seatsUsed } } }
}
)
}

return { prevUser, prevSeat }
},
onError: (_err, _activated, context) => {
queryClient.setQueryData(['SelfHostedCurrentUser'], context.prevUser)
// Rollback the data if the mutation fails
queryClientV5.setQueryData(
SelfHostedCurrentUserQueryOpts({ provider }).queryKey,
context.prevUser
)
queryClientV5.setQueryData(
SelfHostedSeatsConfigQueryOpts({ provider }).queryKey,
context.prevSeat
)
},
onSettled: () => {
queryClient.invalidateQueries(['SelfHostedCurrentUser'])
// Invalidate the queries to ensure they are re-fetched
queryClientV5.invalidateQueries({
queryKey: SelfHostedCurrentUserQueryOpts({ provider }).queryKey,
})
queryClientV5.invalidateQueries(
SelfHostedSeatsConfigQueryOpts({ provider }).queryKey
)
Expand Down
Loading
Loading