Skip to content

Commit

Permalink
Merge branch 'main' into users-developer-plan
Browse files Browse the repository at this point in the history
  • Loading branch information
ajay-sentry committed Feb 4, 2025
2 parents 78021ec + 47e6e13 commit 898fc8d
Show file tree
Hide file tree
Showing 19 changed files with 177 additions and 113 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.2",
"@sentry/react": "^8.35.0",
"@stripe/react-stripe-js": "^2.7.1",
"@stripe/stripe-js": "^3.4.0",
"@stripe/react-stripe-js": "^3.1.1",
"@stripe/stripe-js": "^5.6.0",
"@tanstack/react-query": "^4.29.5",
"@tanstack/react-queryV5": "npm:@tanstack/react-query@^5.59.15",
"@tanstack/react-table": "^8.9.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SubmitHandler, useForm } from 'react-hook-form'
import { useParams } from 'react-router-dom'
import { z } from 'zod'

import { Provider } from 'shared/api/helpers'
import Banner from 'ui/Banner'
import BannerContent from 'ui/Banner/BannerContent'
import Button from 'ui/Button'
Expand All @@ -13,7 +14,7 @@ import Icon from 'ui/Icon'
import TextInput from 'ui/TextInput'
import Toggle from 'ui/Toggle'

import { useUpdateOktaConfig } from '../hooks'
import { useUpdateOktaConfig } from '../hooks/useUpdateOktaConfig'
import { OktaConfigQueryOpts } from '../queries/OktaConfigQueryOpts'

const FormSchema = z.object({
Expand All @@ -24,7 +25,7 @@ const FormSchema = z.object({

type FormValues = z.infer<typeof FormSchema>
interface URLParams {
provider: string
provider: Provider
owner: string
}

Expand Down
1 change: 0 additions & 1 deletion src/pages/AccountSettings/tabs/OktaAccess/hooks/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import {
QueryClientProvider as QueryClientProviderV5,
QueryClient as QueryClientV5,
Expand All @@ -19,9 +18,6 @@ import {
vi.mock('services/toastNotification')
const mockedToastNotification = useAddNotification as Mock

const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
})
const queryClientV5 = new QueryClientV5({
defaultOptions: { queries: { retry: false } },
})
Expand All @@ -30,11 +26,9 @@ const wrapper =
(initialEntries = '/gh/codecov'): React.FC<React.PropsWithChildren> =>
({ children }) => (
<QueryClientProviderV5 client={queryClientV5}>
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={[initialEntries]}>
<Route path="/:provider/:owner">{children}</Route>
</MemoryRouter>
</QueryClientProvider>
<MemoryRouter initialEntries={[initialEntries]}>
<Route path="/:provider/:owner">{children}</Route>
</MemoryRouter>
</QueryClientProviderV5>
)

Expand All @@ -57,7 +51,6 @@ beforeAll(() => {
})

afterEach(() => {
queryClient.clear()
queryClientV5.clear()
server.resetHandlers()
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,53 @@
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 z from 'zod'

import { useAddNotification } from 'services/toastNotification'
import Api from 'shared/api'
import { NetworkErrorObject } from 'shared/api/helpers'
import { Provider, rejectNetworkError } from 'shared/api/helpers'
import A from 'ui/A'

import { OktaConfigQueryOpts } from '../queries/OktaConfigQueryOpts'

const TOAST_DURATION = 10000

const query = `
mutation SaveOktaConfig($input: SaveOktaConfigInput!) {
saveOktaConfig(input: $input) {
error {
__typename
... on UnauthorizedError {
message
__typename
}
... on ValidationError {
message
__typename
}
... on UnauthenticatedError {
__typename
message
}
mutation SaveOktaConfig($input: SaveOktaConfigInput!) {
saveOktaConfig(input: $input) {
error {
__typename
... on UnauthorizedError {
message
}
... on ValidationError {
message
}
... on UnauthenticatedError {
message
}
}
}
`
}`

const ErrorUnionSchema = z.discriminatedUnion('__typename', [
z.object({
__typename: z.literal('UnauthorizedError'),
message: z.string(),
}),
z.object({
__typename: z.literal('ValidationError'),
message: z.string(),
}),
z.object({
__typename: z.literal('UnauthenticatedError'),
message: z.string(),
}),
])

const ResponseSchema = z.object({
saveOktaConfig: z
.object({
error: z
.union([
z.object({
__typename: z.literal('UnauthorizedError'),
message: z.string(),
}),
z.object({
__typename: z.literal('ValidationError'),
message: z.string(),
}),
z.object({
__typename: z.literal('UnauthenticatedError'),
message: z.string(),
}),
])
.nullable(),
})
.nullable(),
saveOktaConfig: z.object({ error: ErrorUnionSchema.nullable() }).nullable(),
})

export const SaveOktaConfigMessage = () => (
Expand All @@ -67,7 +61,7 @@ export const SaveOktaConfigMessage = () => (
)

interface URLParams {
provider: string
provider: Provider
owner: string
}

Expand All @@ -83,7 +77,7 @@ export const useUpdateOktaConfig = ({ provider, owner }: URLParams) => {
const addToast = useAddNotification()
const queryClientV5 = useQueryClientV5()

return useMutation({
return useMutationV5({
mutationFn: ({
clientId,
clientSecret,
Expand All @@ -110,26 +104,21 @@ export const useUpdateOktaConfig = ({ provider, owner }: URLParams) => {
onSuccess: ({ data }) => {
const parsedData = ResponseSchema.safeParse(data)
if (!parsedData.success) {
return Promise.reject({
return rejectNetworkError({
status: 404,
data: {},
dev: 'useUpdateOktaConfig - 404 failed to parse',
} satisfies NetworkErrorObject)
error: parsedData.error,
})
}

const error = parsedData.data.saveOktaConfig?.error
if (error) {
if (
error.__typename === 'ValidationError' ||
error.__typename === 'UnauthorizedError' ||
error.__typename === 'UnauthenticatedError'
) {
addToast({
type: 'error',
text: <SaveOktaConfigMessage />,
disappearAfter: TOAST_DURATION,
})
}
addToast({
type: 'error',
text: <SaveOktaConfigMessage />,
disappearAfter: TOAST_DURATION,
})
} else {
addToast({
type: 'success',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function PaymentCard({ accountDetails, provider, owner }) {
variant="primary"
onClick={() => setIsFormOpen(true)}
>
Set card
Set payment method
</Button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { MemoryRouter } from 'react-router-dom'

import { ThemeContextProvider } from 'shared/ThemeContext'
import { Plans } from 'shared/utils/billing'
Expand Down Expand Up @@ -57,6 +58,7 @@ const subscriptionDetail = {

const accountDetails = {
subscriptionDetail,
activatedUserCount: 1,
}

const usBankSubscriptionDetail = {
Expand All @@ -75,7 +77,9 @@ const usBankSubscriptionDetail = {

const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
<ThemeContextProvider>{children}</ThemeContextProvider>
<MemoryRouter>
<ThemeContextProvider>{children}</ThemeContextProvider>
</MemoryRouter>
</QueryClientProvider>
)

Expand Down Expand Up @@ -383,7 +387,13 @@ describe('PaymentCard', () => {

await user.click(screen.getByTestId('edit-payment-method'))

expect(screen.getByText(randomError)).toBeInTheDocument()
expect(
screen.getByText((content) =>
content.includes(
"There's been an error. Please try refreshing your browser"
)
)
).toBeInTheDocument()
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,15 @@ const mocks = {
useUpdatePaymentMethod: vi.fn(),
}

vi.mock('services/account/useUpdatePaymentMethod', () => ({
useUpdatePaymentMethod: () => mocks.useUpdatePaymentMethod(),
}))
vi.mock('services/account/useUpdatePaymentMethod', async () => {
const original = await vi.importActual(
'services/account/useUpdatePaymentMethod'
)
return {
...original,
useUpdatePaymentMethod: () => mocks.useUpdatePaymentMethod(),
}
})

afterEach(() => {
vi.clearAllMocks()
Expand Down Expand Up @@ -214,7 +220,13 @@ describe('PaymentMethodForm', () => {

await user.click(screen.getByTestId('save-payment-method'))

expect(screen.getByText(randomError)).toBeInTheDocument()
expect(
screen.getByText((content) =>
content.includes(
"There's been an error. Please try refreshing your browser"
)
)
).toBeInTheDocument()
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ import cs from 'classnames'
import { z } from 'zod'

import { AccountDetailsSchema, BillingDetailsSchema } from 'services/account'
import { useUpdatePaymentMethod } from 'services/account/useUpdatePaymentMethod'
import {
MissingAddressError,
MissingEmailError,
MissingNameError,
useUpdatePaymentMethod,
} from 'services/account/useUpdatePaymentMethod'
import { Provider } from 'shared/api/helpers'
import A from 'ui/A'
import Button from 'ui/Button'

interface PaymentMethodFormProps {
Expand Down Expand Up @@ -81,7 +87,7 @@ const PaymentMethodForm = ({
}}
/>
<p className="mt-1 text-ds-primary-red">
{showError && error?.message}
{showError ? getErrorMessage(error) : null}
</p>
<div className="mb-8 mt-4 flex gap-1">
<Button
Expand Down Expand Up @@ -150,4 +156,27 @@ export const getName = (
)
}

export const getErrorMessage = (error: Error): JSX.Element => {
switch (error.message) {
case MissingNameError:
return <span>Missing name, please edit Full Name</span>
case MissingEmailError:
return <span>Missing email, please edit Email</span>
case MissingAddressError:
return <span>Missing address, please edit Address</span>
default:
return (
<span>
There&apos;s been an error. Please try refreshing your browser, if
this error persists please{' '}
{/* @ts-expect-error ignore until we can convert A component to ts */}
<A to={{ pageName: 'support' }} variant="link">
contact support
</A>
.
</span>
)
}
}

export default PaymentMethodForm
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ describe('CurrentOrgPlan', () => {
)
expect(paymentFailed).toBeInTheDocument()
const contactSupport = await screen.findByText(
'Please try a different card or contact support at [email protected].'
'Please try a different payment method or contact support at [email protected].'
)
expect(contactSupport).toBeInTheDocument()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ function CurrentOrgPlan() {
/>
) : null}
<InfoMessageStripeCallback
hasUnverifiedPaymentMethods={hasUnverifiedPaymentMethods}
awaitingInitialPaymentMethodVerification={
awaitingInitialPaymentMethodVerification
}
/>
{isDelinquent ? <DelinquentAlert /> : null}
{data?.plan ? (
Expand Down Expand Up @@ -161,7 +163,8 @@ const DelinquentAlert = () => {
<Alert variant={'error'}>
<Alert.Title>Your most recent payment failed</Alert.Title>
<Alert.Description>
Please try a different card or contact support at [email protected].
Please try a different payment method or contact support at
[email protected].
</Alert.Description>
</Alert>
<br />
Expand Down
Loading

0 comments on commit 898fc8d

Please sign in to comment.