Skip to content

Commit fd99e4c

Browse files
authored
Merge pull request #83 from lidofinance/feature/si-1953-handle-404-for-vaults
Display error for vaults when could not fetch/invalid
2 parents 2fa77ed + c297e30 commit fd99e4c

File tree

6 files changed

+92
-14
lines changed

6 files changed

+92
-14
lines changed

modules/vaults/consts/texts.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ export const vaultTexts = {
315315

316316
noRoles: (roleNames: string[]) =>
317317
`You don't have ${roleNames.join(',')} role${roleNames.length > 1 ? 's' : ''}` as const,
318+
loadingVault: 'Error loading stVault',
319+
vaultAddress: 'Invalid stVault address',
320+
},
321+
links: {
322+
goToAll: 'To All Vaults',
318323
},
319324
},
320325
} as const;

modules/vaults/vault-context/index.tsx

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import invariant from 'tiny-invariant';
12
import {
23
FC,
34
createContext,
@@ -8,10 +9,11 @@ import {
89
} from 'react';
910
import { useRouter } from 'next/router';
1011
import { Address, isAddress } from 'viem';
11-
import invariant from 'tiny-invariant';
12+
import type { QueryObserverResult } from '@tanstack/react-query';
13+
1214
import { useSingleVaultData } from 'modules/vaults/hooks/use-vault-data';
13-
import { VaultInfo } from 'types';
14-
import { QueryObserverResult } from '@tanstack/react-query';
15+
16+
import type { VaultInfo } from 'types';
1517

1618
type VaultContextType = {
1719
vaultAddress: Address | undefined;
@@ -23,11 +25,18 @@ type VaultContextType = {
2325
const VaultContext = createContext<VaultContextType | null>(null);
2426
VaultContext.displayName = 'VaultContext';
2527

28+
export class VaultAddressError extends Error {
29+
constructor(vaultAddress: string) {
30+
super(`Vault address is not valid: ${vaultAddress}`);
31+
this.name = 'VaultAddressError';
32+
}
33+
}
34+
2635
export const VaultProvider: FC<PropsWithChildren> = ({ children }) => {
2736
const router = useRouter();
2837
const { vaultAddress = '' } = router.query as { vaultAddress?: Address };
29-
const sanitizedVaultAddress = isAddress(vaultAddress)
30-
? vaultAddress
38+
const sanitizedVaultAddress = isAddress(vaultAddress.toLowerCase())
39+
? (vaultAddress.toLowerCase() as Address)
3140
: undefined;
3241
const { data, error, refetch, isPending, isRefetching } = useSingleVaultData(
3342
sanitizedVaultAddress,
@@ -43,12 +52,26 @@ export const VaultProvider: FC<PropsWithChildren> = ({ children }) => {
4352
vaultAddress: sanitizedVaultAddress,
4453
activeVault: data,
4554
isLoadingVault: isPending,
46-
error: error,
55+
56+
error:
57+
error ||
58+
(vaultAddress &&
59+
!sanitizedVaultAddress &&
60+
new VaultAddressError(vaultAddress)) ||
61+
null,
4762
refetchVaultInfo: () =>
4863
refetch({ cancelRefetch: true, throwOnError: false }),
4964
isRefetching: isRefetching,
5065
};
51-
}, [sanitizedVaultAddress, data, isPending, error, isRefetching, refetch]);
66+
}, [
67+
sanitizedVaultAddress,
68+
data,
69+
isPending,
70+
error,
71+
vaultAddress,
72+
isRefetching,
73+
refetch,
74+
]);
5275

5376
return (
5477
<VaultContext.Provider value={contextValue}>

shared/components/button-link/button-link.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const ButtonLink: FC<PropsWithChildren<CloseButtonProps>> = ({
2020
);
2121

2222
if (href) {
23-
<Link href={href}>{content}</Link>;
23+
return <Link href={href}>{content}</Link>;
2424
}
2525

2626
return content;

shared/components/layout/navigation/modes/vault.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
import { Stake, Withdraw, Wrap } from '@lidofinance/lido-ui';
2-
import { appPaths } from 'consts/routing';
1+
import { useMemo } from 'react';
32
import { type Address } from 'viem';
4-
import { NavList, SelectedVaultWrapper } from '../styles';
3+
import { Stake, Withdraw, Wrap } from '@lidofinance/lido-ui';
4+
55
import { useVaultInfo } from 'modules/vaults';
66
import { AddressBadge } from 'shared/components/address-badge';
7-
import { useMemo } from 'react';
8-
import { ReactComponent as GearIcon } from 'assets/icons/gear.svg';
9-
import { ReactComponent as MosaicIcon } from 'assets/icons/mosaic.svg';
7+
import { appPaths } from 'consts/routing';
8+
109
import { NavigationLink } from '../navigation-link';
1110
import { BackAllVaults } from '../back-all-vaults';
11+
import { NavList, SelectedVaultWrapper } from '../styles';
12+
13+
import { ReactComponent as GearIcon } from 'assets/icons/gear.svg';
14+
import { ReactComponent as MosaicIcon } from 'assets/icons/mosaic.svg';
15+
import { VaultError } from '../vault-error';
1216

1317
const vaultRoutes = (vaultAddress: Address, overrideMode?: any) => [
1418
{
@@ -82,6 +86,7 @@ export const VaultNavigation = () => {
8286
/>
8387
))}
8488
</NavList>
89+
<VaultError />
8590
</>
8691
);
8792
};

shared/components/layout/navigation/styles.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,11 @@ export const SelectedVaultWrapper = styled.div`
122122
background-color: var(--lido-color-background);
123123
overflow: clip;
124124
`;
125+
126+
// Error modal
127+
128+
export const ErrorModalContent = styled.div`
129+
display: flex;
130+
flex-direction: column;
131+
gap: ${({ theme }) => theme.spaceMap.sm}px;
132+
`;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Modal, Button } from '@lidofinance/lido-ui';
2+
3+
import { useVaultInfo, VaultAddressError, vaultTexts } from 'modules/vaults';
4+
import { ButtonLink } from 'shared/components/button-link';
5+
import { appPaths } from 'consts/routing';
6+
7+
import { ErrorModalContent } from './styles';
8+
9+
const texts = vaultTexts.common;
10+
11+
export const VaultError = () => {
12+
const { error, refetchVaultInfo } = useVaultInfo();
13+
if (!error) return null;
14+
15+
const goToAll = (
16+
<ButtonLink href={appPaths.vaults.all}>{texts.links.goToAll}</ButtonLink>
17+
);
18+
19+
if (error instanceof VaultAddressError) {
20+
return (
21+
<Modal title={texts.errors.vaultAddress} center open>
22+
{goToAll}
23+
</Modal>
24+
);
25+
}
26+
27+
return (
28+
<Modal title={texts.errors.loadingVault} center open>
29+
<ErrorModalContent>
30+
<Button variant="outlined" onClick={() => refetchVaultInfo()}>
31+
Try Again
32+
</Button>
33+
{goToAll}
34+
</ErrorModalContent>
35+
</Modal>
36+
);
37+
};

0 commit comments

Comments
 (0)