Skip to content

Commit

Permalink
feat: add Prime Simulator blank page (#1910)
Browse files Browse the repository at this point in the history
  • Loading branch information
therealemjy authored Dec 7, 2023
1 parent bec8ac3 commit 0ea2c60
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 16 deletions.
42 changes: 38 additions & 4 deletions src/App/Router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ const Vaults = lazy(() => import('pages/Vault'));
const Voter = lazy(() => import('pages/Voter'));
const VoterLeaderboard = lazy(() => import('pages/VoterLeaderboard'));
const Xvs = lazy(() => import('pages/Xvs'));
const PrimeSimulator = lazy(() => import('pages/PrimeSimulator'));

const Router = () => {
const { accountAddress } = useAccountAddress();
const historyRouteEnabled = useIsFeatureEnabled({ name: 'historyRoute' });
const convertVrtRouteEnabled = useIsFeatureEnabled({ name: 'convertVrtRoute' });
const vaiRouteEnabled = useIsFeatureEnabled({ name: 'vaiRoute' });
const xvsRouteEnabled = useIsFeatureEnabled({ name: 'xvsRoute' });
const primeEnabled = useIsFeatureEnabled({ name: 'prime' });
const location = useLocation();
const navigate = useNavigate();

Expand All @@ -56,17 +58,28 @@ const Router = () => {
return (
<Routes>
<Route
path={routes.dashboard.path}
path={`${routes.dashboard.path}/*`}
element={
<PageSuspense>
<Dashboard />
</PageSuspense>
}
/>

{primeEnabled && (
<Route
path={routes.dashboardPrimeSimulator.path}
element={
<PageSuspense>
<PrimeSimulator />
</PageSuspense>
}
/>
)}

{!!accountAddress && (
<Route
path={routes.account.path}
path={`${routes.account.path}/*`}
element={
<PageSuspense>
<Account />
Expand All @@ -75,6 +88,17 @@ const Router = () => {
/>
)}

{!!accountAddress && primeEnabled && (
<Route
path={routes.accountPrimeSimulator.path}
element={
<PageSuspense>
<PrimeSimulator />
</PageSuspense>
}
/>
)}

<Route
path={routes.isolatedPools.path}
element={
Expand Down Expand Up @@ -121,14 +145,25 @@ const Router = () => {
/>

<Route
path={routes.vaults.path}
path={`${routes.vaults.path}/*`}
element={
<PageSuspense>
<Vaults />
</PageSuspense>
}
/>

{primeEnabled && (
<Route
path={routes.vaultsPrimeSimulator.path}
element={
<PageSuspense>
<PrimeSimulator />
</PageSuspense>
}
/>
)}

{historyRouteEnabled && (
<Route
path={routes.history.path}
Expand All @@ -140,7 +175,6 @@ const Router = () => {
/>
)}

{/* suffix with a /* to make it accept nested routes */}
<Route
path={`${routes.governance.path}/*`}
element={
Expand Down
6 changes: 5 additions & 1 deletion src/constants/routing.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export enum Subdirectory {
DASHBOARD = '/',
DASHBOARD = '',
ACCOUNT = '/account',
XVS = '/xvs',
CORE_POOL = '/core-pool',
Expand All @@ -21,11 +21,14 @@ export enum Subdirectory {
SWAP = '/swap',
CONVERT_VRT = '/convert-vrt',
VAI = '/vai',
PRIME_SIMULATOR = '/prime-simulator',
}

const routeSubdirectories = {
dashboard: [Subdirectory.DASHBOARD],
dashboardPrimeSimulator: [Subdirectory.DASHBOARD, Subdirectory.PRIME_SIMULATOR],
account: [Subdirectory.ACCOUNT],
accountPrimeSimulator: [Subdirectory.ACCOUNT, Subdirectory.PRIME_SIMULATOR],
xvs: [Subdirectory.XVS],
isolatedPools: [Subdirectory.ISOLATED_POOLS],
corePool: [Subdirectory.CORE_POOL],
Expand All @@ -49,6 +52,7 @@ const routeSubdirectories = {
swap: [Subdirectory.SWAP],
convertVrt: [Subdirectory.CONVERT_VRT],
vaults: [Subdirectory.VAULTS],
vaultsPrimeSimulator: [Subdirectory.VAULTS, Subdirectory.PRIME_SIMULATOR],
vai: [Subdirectory.VAI],
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: / 1`] = `"Dashboard"`;
exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: 1`] = `"Dashboard"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /account 1`] = `"Account"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /account/prime-simulator 1`] = `"Account/Prime simulator"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /convert-vrt 1`] = `"Convert VRT"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /core-pool 1`] = `"Core pool"`;
Expand All @@ -26,10 +28,14 @@ exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on th

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /isolated-pools/pool/0x3d759121234cd36F8124C21aFe1c6852d2bEd848/market/0x6d6F697e34145Bb95c54E77482d97cc261Dc237E 1`] = `"Isolated pools/Venus/XVS"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /prime-simulator 1`] = `"Dashboard/Prime simulator"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /swap 1`] = `"Swap"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /vai 1`] = `"VAI"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /vaults 1`] = `"Vaults"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /vaults/prime-simulator 1`] = `"Vaults/Prime simulator"`;

exports[`component/Layout/Header/Breadcrumbs > outputs the right DOM based on the current path: /xvs 1`] = `"XVS"`;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { renderComponent } from 'testUtils/render';
import { useGetPool, useGetVTokens } from 'clients/api';
import { routes } from 'constants/routing';

import { Breadcrumbs } from '.';
import { Breadcrumbs } from '..';

describe('component/Layout/Header/Breadcrumbs', () => {
beforeEach(() => {
Expand Down Expand Up @@ -59,6 +59,9 @@ describe('component/Layout/Header/Breadcrumbs', () => {
[routes.vaults.path, routes.vaults.path],
[routes.convertVrt.path, routes.convertVrt.path],
[routes.swap.path, routes.swap.path],
[routes.accountPrimeSimulator.path, routes.accountPrimeSimulator.path],
[routes.dashboardPrimeSimulator.path, routes.dashboardPrimeSimulator.path],
[routes.vaultsPrimeSimulator.path, routes.vaultsPrimeSimulator.path],
])('outputs the right DOM based on the current path: %s', async (pathname, originalRoute) => {
const { container } = renderComponent(<Breadcrumbs />, {
routerInitialEntries: [pathname],
Expand Down
3 changes: 3 additions & 0 deletions src/containers/Layout/Breadcrumbs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ export const Breadcrumbs: React.FC = () => {
case Subdirectory.VAI:
dom = t('breadcrumbs.vai');
break;
case Subdirectory.PRIME_SIMULATOR:
dom = t('breadcrumbs.primeSimulator');
break;
default:
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Icon, Link, Tooltip } from 'components';
import { PRIME_DOC_URL } from 'constants/prime';
import useFormatPercentageToReadableValue from 'hooks/useFormatPercentageToReadableValue';
import useFormatTokensToReadableValue from 'hooks/useFormatTokensToReadableValue';
import { usePrimeSimulationPagePath } from 'hooks/usePrimeSimulationPagePath';
import { useTranslation } from 'packages/translations';
import { PrimeSimulationDistribution, Token } from 'types';

Expand All @@ -21,6 +21,7 @@ export const ApyWithPrimeSimulationBoost: React.FC<ApyWithPrimeSimulationBoostPr
xvs,
}) => {
const { t, Trans } = useTranslation();
const primeSimulationPageUrl = usePrimeSimulationPagePath();

const readablePrimeApy = useFormatPercentageToReadableValue({
value: primeSimulationDistribution.apyPercentage,
Expand Down Expand Up @@ -69,7 +70,7 @@ export const ApyWithPrimeSimulationBoost: React.FC<ApyWithPrimeSimulationBoostPr
xvsStaked: readableReferenceXvsStaked,
}}
components={{
Link: <Link href={PRIME_DOC_URL} onClick={e => e.stopPropagation()} />,
Link: <Link to={primeSimulationPageUrl} onClick={e => e.stopPropagation()} />,
}}
/>
}
Expand Down
6 changes: 4 additions & 2 deletions src/containers/PrimeStatusBanner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import {
useGetXvsVaultUserInfo,
} from 'clients/api';
import { Card, Link, PrimaryButton, ProgressBar } from 'components';
import { PRIME_DOC_URL } from 'constants/prime';
import { routes } from 'constants/routing';
import useFormatPercentageToReadableValue from 'hooks/useFormatPercentageToReadableValue';
import useConvertMantissaToReadableTokenString from 'hooks/useFormatTokensToReadableValue';
import { usePrimeSimulationPagePath } from 'hooks/usePrimeSimulationPagePath';
import { displayMutationError } from 'packages/errors';
import { useGetToken } from 'packages/tokens';
import { useTranslation } from 'packages/translations';
Expand Down Expand Up @@ -146,6 +146,8 @@ export const PrimeStatusBannerUi: React.FC<PrimeStatusBannerUiProps> = ({
t,
]);

const primeSimulationPageUrl = usePrimeSimulationPagePath();

const displayProgress = !isUserXvsStakeHighEnoughForPrime;
const displayWarning = haveAllPrimeTokensBeenClaimed;
const displayStakeButton =
Expand Down Expand Up @@ -218,7 +220,7 @@ export const PrimeStatusBannerUi: React.FC<PrimeStatusBannerUiProps> = ({
i18nKey="primeStatusBanner.description"
components={{
WhiteText: <span className="text-offWhite" />,
Link: <Link href={PRIME_DOC_URL} />,
Link: <Link to={primeSimulationPageUrl} />,
}}
values={{
stakeDelta: readableStakeDeltaTokens,
Expand Down
35 changes: 35 additions & 0 deletions src/hooks/usePrimeSimulationPagePath/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { matchPath, useLocation } from 'react-router';
import Vi from 'vitest';

import { renderHook } from 'testUtils/render';

import { routes } from 'constants/routing';

import { usePrimeSimulationPagePath } from '..';

vi.mock('react-router', () => ({
...vi.importActual('react-router'),
useLocation: vi.fn(),
matchPath: vi.fn(),
}));

describe('usePrimeSimulationPagePath', () => {
beforeEach(() => {
(matchPath as Vi.Mock).mockImplementation((a, b) => a === b);
});

it.each([
{ pathname: routes.account.path, expectedResult: routes.accountPrimeSimulator.path },
{ pathname: routes.vaults.path, expectedResult: routes.vaultsPrimeSimulator.path },
{ pathname: '/fake/path', expectedResult: routes.dashboardPrimeSimulator.path },
])(
'should return the right path based on the current location %s',
({ pathname, expectedResult }) => {
(useLocation as Vi.Mock).mockImplementation(() => ({ pathname }));

const { result } = renderHook(() => usePrimeSimulationPagePath());

expect(result.current).toBe(expectedResult);
},
);
});
20 changes: 20 additions & 0 deletions src/hooks/usePrimeSimulationPagePath/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useMemo } from 'react';
import { matchPath, useLocation } from 'react-router';

import { routes } from 'constants/routing';

export const usePrimeSimulationPagePath = () => {
const { pathname } = useLocation();

return useMemo(() => {
if (matchPath(routes.account.path, pathname)) {
return routes.accountPrimeSimulator.path;
}

if (matchPath(routes.vaults.path, pathname)) {
return routes.vaultsPrimeSimulator.path;
}

return routes.dashboardPrimeSimulator.path;
}, [pathname]);
};
7 changes: 4 additions & 3 deletions src/packages/translations/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
"isolatedPools": "Isolated pools",
"leaderboard": "Leaderboard",
"markets": "Markets",
"primeSimulator": "Prime simulator",
"proposal": "Proposal #{{proposalId}}",
"swap": "Swap",
"vai": "VAI",
Expand Down Expand Up @@ -184,7 +185,7 @@
"title": "Connect your wallet"
},
"primePromotionalBanner": {
"buttonLabel": "Learn more",
"buttonLabel": "Calculate your Prime rewards",
"description": "Venus Prime and the Venus Prime Token reward dedicated users of Venus with real yield for superior rates with their lending and borrowing activities.",
"illustration": {
"alt": "Prime promotional banner"
Expand Down Expand Up @@ -398,7 +399,7 @@
},
"primeSimulationBoost": {
"label": "{{apyPrimeBoost}} Prime boost",
"tooltip": "Prime boost based on the median user supply of {{supplyBalance}}, borrow of {{borrowBalance}} and vault stake of {{xvsStaked}}. <Link>Learn more about Prime</Link>"
"tooltip": "Prime boost based on the median user supply of {{supplyBalance}}, borrow of {{borrowBalance}} and vault stake of {{xvsStaked}}. <Link>Calculate your Prime rewards</Link>"
}
},
"columnKeys": {
Expand Down Expand Up @@ -566,7 +567,7 @@
"primeStatusBanner": {
"becomePrimeTitle": "You can now become a Prime user",
"claimButtonLabel": "Claim Prime token",
"description": "Stake <WhiteText>{{stakeDelta}}</WhiteText> more then wait {{claimWaitingPeriod}} to claim your Prime token and boost your earnings. <Link>Learn more</Link>",
"description": "Stake <WhiteText>{{stakeDelta}}</WhiteText> more then wait {{claimWaitingPeriod}} to claim your Prime token and boost your earnings. <Link>Calculate your Prime rewards</Link>",
"noPrimeTokenWarning": {
"text": "All Prime tokens have been claimed",
"tooltip": "All {{primeTokenLimit}} Prime tokens are currently claimed. Some may become available if owners no longer meet the eligibility criteria or if we add more."
Expand Down
8 changes: 6 additions & 2 deletions src/pages/Dashboard/Banner/PrimePromotionalBanner/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ButtonWrapper, Card, Icon, Link } from 'components';
import { PRIME_DOC_URL } from 'constants/prime';
import { usePrimeSimulationPagePath } from 'hooks/usePrimeSimulationPagePath';
import { useTranslation } from 'packages/translations';

import boostsIllustration from './boostsIllustration.png';
Expand All @@ -13,6 +13,7 @@ export interface PrimePromotionalBannerProps {

export const PrimePromotionalBanner: React.FC<PrimePromotionalBannerProps> = ({ onHide }) => {
const { t, Trans } = useTranslation();
const primeSimulationPageUrl = usePrimeSimulationPagePath();

return (
<Card className="relative mb-8 overflow-hidden border border-lightGrey py-6 sm:p-0 md:p-0">
Expand Down Expand Up @@ -66,7 +67,10 @@ export const PrimePromotionalBanner: React.FC<PrimePromotionalBannerProps> = ({
</p>

<ButtonWrapper variant="secondary" className="w-full sm:w-auto" asChild>
<Link href={PRIME_DOC_URL} className="text-offWhite no-underline hover:no-underline">
<Link
to={primeSimulationPageUrl}
className="text-offWhite no-underline hover:no-underline"
>
{t('dashboard.primePromotionalBanner.buttonLabel')}
</Link>
</ButtonWrapper>
Expand Down
3 changes: 3 additions & 0 deletions src/pages/PrimeSimulator/Form/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Card } from 'components';

export const Form: React.FC = () => <Card>Form</Card>;
3 changes: 3 additions & 0 deletions src/pages/PrimeSimulator/RewardDetails/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Card } from 'components';

export const RewardDetails: React.FC = () => <Card>RewardDetails</Card>;
9 changes: 9 additions & 0 deletions src/pages/PrimeSimulator/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { renderComponent } from 'testUtils/render';

import PrimeSimulator from '..';

describe('PrimeSimulator', () => {
it('renders without crashing', async () => {
renderComponent(<PrimeSimulator />);
});
});
12 changes: 12 additions & 0 deletions src/pages/PrimeSimulator/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Form } from './Form';
import { RewardDetails } from './RewardDetails';

const PrimeSimulator: React.FC = () => (
<div className="space-y-4 lg:grid lg:grid-cols-2 lg:gap-6 lg:space-y-0">
<Form />

<RewardDetails />
</div>
);

export default PrimeSimulator;

0 comments on commit 0ea2c60

Please sign in to comment.