Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

feat: show alert when detecting API errors (in pool and pool list pages) #764

Closed
wants to merge 4 commits into from
Closed
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
5 changes: 5 additions & 0 deletions lib/modules/pool/PoolList/PoolListProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { usePoolListQueryState } from './usePoolListQueryState'
import { useMandatoryContext } from '@/lib/shared/utils/contexts'
import { useUserAccount } from '../../web3/UserAccountProvider'
import { isAddress } from 'viem'
import { ApiErrorAlert } from '@/lib/shared/components/errors/ApiErrorAlert'

export function _usePoolList({ fixedPoolTypes }: { fixedPoolTypes?: GqlPoolType[] } = {}) {
const { queryVariables, toggleUserAddress } = usePoolListQueryState()
Expand Down Expand Up @@ -59,6 +60,10 @@ export function PoolListProvider({
}: PropsWithChildren<{ fixedPoolTypes?: GqlPoolType[] }>) {
const hook = _usePoolList({ fixedPoolTypes })

if (hook.error) {
return <ApiErrorAlert />
}

return <PoolListContext.Provider value={hook}>{children}</PoolListContext.Provider>
}

Expand Down
9 changes: 8 additions & 1 deletion lib/modules/pool/PoolProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { calcBptPriceFor, usePoolHelpers } from './pool.helpers'
import { useUserAccount } from '@/lib/modules/web3/UserAccountProvider'
import { usePoolEnrichWithOnChainData } from '@/lib/modules/pool/queries/usePoolEnrichWithOnChainData'
import { useOnchainUserPoolBalances } from './queries/useOnchainUserPoolBalances'
import { ApiErrorAlert } from '@/lib/shared/components/errors/ApiErrorAlert'
import { useInvalidVariantRedirect } from './pool.hooks'

export type UsePoolResponse = ReturnType<typeof _usePool> & {
Expand All @@ -36,7 +37,7 @@ export function _usePool({

const myLiquiditySectionRef = useRef<HTMLDivElement | null>(null)

const { data } = useQuery(GetPoolDocument, {
const { data, error } = useQuery(GetPoolDocument, {
variables: queryVariables,
})

Expand Down Expand Up @@ -76,6 +77,7 @@ export function _usePool({
// this assumption may need to be questioned
refetch,
...usePoolHelpers(pool, chain),
error,
}
}

Expand All @@ -87,6 +89,11 @@ export function PoolProvider({
data,
}: PropsWithChildren<FetchPoolProps> & { data: GetPoolQuery }) {
const hook = _usePool({ id, chain, variant, initialData: data })

if (hook.error) {
return <ApiErrorAlert />
}

const payload = {
...hook,
chain,
Expand Down
7 changes: 7 additions & 0 deletions lib/shared/components/errors/ApiErrorAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { GlobalAlert } from './GlobalAlert'

export function ApiErrorAlert() {
return (
<GlobalAlert title={'Our API data provider appears to be having issues...'} status="error" />
)
}
47 changes: 47 additions & 0 deletions lib/shared/components/errors/GlobalAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Alert, AlertTitle, HStack, Box, AlertStatus } from '@chakra-ui/react'
import { AlertTriangle } from 'react-feather'
import { useThemeColorMode } from '../../services/chakra/useThemeColorMode'
import { ReactNode } from 'react'
export type AlertProps = {
title: ReactNode | string
status: AlertStatus
}

// TODO: this component has many similarities with the PoolAlert component
// Decide if we want to merge them or keep them separate
export function GlobalAlert({ title, status }: AlertProps) {
const colorMode = useThemeColorMode()

return (
<Alert
display="flex"
justifyContent="space-between"
bg={colorMode === 'dark' ? 'orange.300' : 'orange.200'}
status={status}
rounded="lg"
border="none !important"
alignItems="center"
color="font.dark"
role="group"
margin="md"
>
<HStack w="full">
<Box flex="0 0 auto">
<AlertTriangle width="24px" height="24px" />
</Box>
<AlertTitle
w="full"
gap={1}
display="flex"
alignItems="center"
ml="md"
sx={{ a: { textDecoration: 'underline' } }}
fontWeight={500}
color="font.dark"
>
{title}
</AlertTitle>
</HStack>
</Alert>
)
}
19 changes: 18 additions & 1 deletion lib/shared/services/api/apollo.client.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { config } from '@/lib/config/app.config'
import { ApolloLink, HttpLink } from '@apollo/client'
import { onError } from '@apollo/client/link/error'

import {
NextSSRApolloClient,
NextSSRInMemoryCache,
SSRMultipartLink,
} from '@apollo/experimental-nextjs-app-support/ssr'
import { captureException } from '@sentry/nextjs'

/*const userMiddleware = new ApolloLink((operation, forward) => {
// add the user address to the headers
Expand All @@ -25,6 +28,19 @@ export function createApolloClient() {
//const keyArgs = ['where', ['poolIdIn']]
const httpLink = new HttpLink({ uri: config.apiUrl })

const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message }) => {
captureException(new Error(message), { level: 'fatal' })
})
}

if (networkError) {
// For now we use fatal level, we can adjust this if it becomes noisy
captureException(networkError, { level: 'fatal' })
}
})

return new NextSSRApolloClient({
ssrMode: typeof window === 'undefined',
link:
Expand All @@ -34,8 +50,9 @@ export function createApolloClient() {
stripDefer: true,
}),
httpLink,
errorLink,
])
: httpLink,
: ApolloLink.from([httpLink, errorLink]),
cache: new NextSSRInMemoryCache({
typePolicies: {
GqlToken: {
Expand Down
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { withSentryConfig } = require('@sentry/nextjs')
const { sentryOptions } = require('./sentry.config')

Expand Down
Loading