feat: add views

This commit is contained in:
bartosz-lipinski 2020-11-17 22:15:03 -06:00
parent 2579c4a1bc
commit 856329b151
20 changed files with 254 additions and 32 deletions

View File

@ -1,4 +1,4 @@
@import "~antd/dist/antd.dark.less";
@import "~antd/dist/antd.less";
@import "./ant-custom.less";
body {

View File

@ -1,4 +1,4 @@
@import "~antd/dist/antd.css";
@import "~antd/dist/antd.dark.less";
@import "~antd/dist/antd.less";
@primary-color: #ff00a8;
@popover-background: #1a2029;

View File

@ -6,7 +6,8 @@ import {
PieChartOutlined,
GithubOutlined,
BankOutlined,
LogoutOutlined
LogoutOutlined,
HomeOutlined
} from '@ant-design/icons';
import BasicLayout, { DefaultFooter, PageContainer } from '@ant-design/pro-layout';
@ -34,15 +35,42 @@ export const AppLayout = (props: any) => {
]}
menuContentRender={() => {
return <Menu theme="dark" defaultSelectedKeys={['1']} mode="inline">
<Menu.Item key="1" icon={<BankOutlined />}>
Deposit
</Menu.Item>
<Menu.Item key="2" icon={<LogoutOutlined />}>
Borrow
</Menu.Item>
<Menu.Item key="3" icon={<PieChartOutlined />}>
Dashboard
</Menu.Item>
<Menu.Item key="1" icon={<HomeOutlined />}>
<Link
to={{
pathname: "/",
}}
>
Home
</Link>
</Menu.Item>
<Menu.Item key="2" icon={<PieChartOutlined />}>
<Link
to={{
pathname: "/dashboard",
}}
>
Dashboard
</Link>
</Menu.Item>
<Menu.Item key="3" icon={<BankOutlined />}>
<Link
to={{
pathname: "/deposit",
}}
>
Deposit
</Link>
</Menu.Item>
<Menu.Item key="4" icon={<LogoutOutlined />}>
<Link
to={{
pathname: "/borrow",
}}
>
Borrow
</Link>
</Menu.Item>
</Menu>
}}
>

View File

@ -5,7 +5,7 @@ import { useConnectionConfig } from "../../contexts/connection";
import { PublicKey } from "@solana/web3.js";
export const TokenIcon = (props: {
mintAddress: string | PublicKey;
mintAddress?: string | PublicKey;
style?: React.CSSProperties;
className?: string;
}) => {

View File

@ -1,13 +1,14 @@
import { PublicKey } from "@solana/web3.js";
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
import { LendingReserveParser } from "../models/lending";
import { cache } from './../contexts/accounts';
import { LendingReserve, LendingReserveParser } from "../models/lending";
import { cache, ParsedAccount } from './../contexts/accounts';
const getLendingReserves = () => {
return cache.byParser(LendingReserveParser).map(id => cache.get(id)).filter(acc => acc !== undefined) as any[];
};
export function useLendingReserves() {
const [reserveAccounts, setReserveAccounts] = useState<any[]>([]);
const [reserveAccounts, setReserveAccounts] = useState<ParsedAccount<LendingReserve>[]>([]);
useEffect(() => {
setReserveAccounts(getLendingReserves());
@ -26,4 +27,25 @@ export function useLendingReserves() {
return {
reserveAccounts,
};
}
export function useLendingReserve(address: string | PublicKey) {
const id = typeof address === 'string' ? address : address?.toBase58();
const [reserveAccount, setReserveAccount] = useState<ParsedAccount<LendingReserve>>();
useEffect(() => {
setReserveAccount(cache.get(id));
const dispose = cache.emitter.onCache((args) => {
if (args.id === id) {
setReserveAccount(cache.get(id));
}
});
return () => {
dispose();
};
}, [setReserveAccount])
return reserveAccount;
}

View File

@ -2,7 +2,7 @@ import { PublicKey } from "@solana/web3.js";
import { useConnectionConfig } from "../contexts/connection";
import { getTokenName } from "../utils/utils";
export function useTokenName(mintAddress: string | PublicKey) {
export function useTokenName(mintAddress?: string | PublicKey) {
const { tokenMap } = useConnectionConfig();
const address = typeof mintAddress === 'string' ? mintAddress : mintAddress?.toBase58();
return getTokenName(tokenMap, address);

View File

@ -4,7 +4,7 @@ import { useMint } from "../contexts/accounts";
import { convert } from "../utils/utils";
import { useUserAccounts } from "./useUserAccounts";
export function useUserBalance(mint: PublicKey) {
export function useUserBalance(mint?: PublicKey) {
const { userAccounts } = useUserAccounts();
const mintInfo = useMint(mint);

View File

@ -1,4 +1,4 @@
import { HashRouter, Route } from "react-router-dom";
import { HashRouter, Route, Switch } from "react-router-dom";
import React from "react";
import { WalletProvider } from "./contexts/wallet";
import { ConnectionProvider } from "./contexts/connection";
@ -7,7 +7,14 @@ import { MarketProvider } from "./contexts/market";
import { LendingProvider } from "./contexts/lending";
import { AppLayout } from "./components/Layout";
import { DepositList } from './views/deposit/list/list';
import {
HomeView,
DepositView,
DepositAddView,
BorrowView,
ReserveView,
DashboardView,
} from './views';
export function Routes() {
return (
@ -19,7 +26,14 @@ export function Routes() {
<MarketProvider>
<LendingProvider>
<AppLayout>
<Route exact path="/" component={() => <DepositList />} />
<Switch>
<Route exact path="/" component={() => <HomeView />} />
<Route exact path="/dashboard" children={<DashboardView />} />
<Route path="/reserve/:id" children={<ReserveView />} />
<Route exact path="/deposit" component={() => <DepositView />} />
<Route path="/deposit/:id" children={<DepositAddView />} />
<Route exact path="/borrow" children={<BorrowView />} />
</Switch>
</AppLayout>
</LendingProvider>
</MarketProvider>

View File

@ -49,9 +49,13 @@ export function shortenAddress(address: string, chars = 4): string {
export function getTokenName(
map: KnownTokenMap,
mintAddress: string,
mintAddress?: string,
shorten = true
): string {
if(!mintAddress) {
return 'N/A';
}
const knownSymbol = map.get(mintAddress)?.tokenSymbol;
if (knownSymbol) {
return knownSymbol;
@ -62,9 +66,13 @@ export function getTokenName(
export function getTokenIcon(
map: KnownTokenMap,
mintAddress: string | PublicKey,
mintAddress?: string | PublicKey,
): string | undefined {
const address = typeof mintAddress === 'string' ? mintAddress : mintAddress?.toBase58();
if(!address) {
return;
}
return map.get(address)?.icon;
}

View File

View File

@ -0,0 +1,13 @@
import React, { useMemo } from "react";
import { useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button } from "antd";
export const BorrowView = () => {
return <div style={{ display: 'flex', justifyContent: 'space-around' }}>
Borrow
</div>;
}

View File

@ -0,0 +1,14 @@
import React, { useMemo } from "react";
import { useLendingReserves, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button } from "antd";
export const DashboardView = () => {
const { reserveAccounts } = useLendingReserves();
return <div>
DASHBOARD
</div>;
}

View File

@ -0,0 +1,29 @@
import React, { useMemo } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from './../../../hooks';
import { LendingReserve, LendingReserveParser } from "../../../models/lending";
import { TokenIcon } from "../../../components/TokenIcon";
import { formatNumber } from "../../../utils/utils";
import { Button } from "antd";
import { useParams } from "react-router-dom";
import { useAccount } from "../../../contexts/accounts";
export const DepositAddView = () => {
const { id } = useParams<{ id: string }>();
const lendingReserve = useLendingReserve(id);
const reserve = lendingReserve?.info;
const name = useTokenName(reserve?.liquidityMint);
const tokenBalance = useUserBalance(reserve?.liquidityMint);
const collateralBalance = useUserBalance(reserve?.collateralMint);
return <div style={{ display: 'flex', justifyContent: 'space-around' }}>
<TokenIcon mintAddress={reserve?.liquidityMint} />
{name}
<div>{formatNumber.format(tokenBalance)} {name}</div>
<div>{formatNumber.format(collateralBalance)} {name}</div>
<div>--</div>
<Button>Deposit</Button>
ADD: {id}
</div>;
}

View File

@ -0,0 +1,2 @@
export * from './view';
export * from './add';

View File

@ -1,23 +1,24 @@
import React from "react";
import { Input } from "antd";
import { useLendingReserves, useTokenName } from './../../../hooks';
import { useLendingReserves, useTokenName } from '../../../hooks';
import { LendingReserve } from "../../../models/lending";
import { getTokenName } from "../../../utils/utils";
import { useConnectionConfig } from "../../../contexts/connection";
import { TokenIcon } from "../../../components/TokenIcon";
import { ReserveItem } from './item';
export const DepositList = () => {
export const DepositView = () => {
const { reserveAccounts } = useLendingReserves();
return (
<div>
<div style={{ display: 'flex' }}>
<div style={{ display: 'flex', justifyContent: 'space-around' }}>
<div>Asset</div>
<div>Your wallet balance</div>
<div>Your balance in Oyster</div>
<div>APY</div>
<div>Action</div>
</div>
{reserveAccounts.map(account => <ReserveItem reserve={account.info} />)}
{reserveAccounts.map(account => <ReserveItem reserve={account.info} address={account.pubkey} />)}
</div>
);
};

View File

@ -1,20 +1,26 @@
import React, { useMemo } from "react";
import { useTokenName, useUserAccounts, useUserBalance } from './../../../hooks';
import { useTokenName, useUserAccounts, useUserBalance } from '../../../hooks';
import { LendingReserve } from "../../../models/lending";
import { TokenIcon } from "../../../components/TokenIcon";
import { formatNumber } from "../../../utils/utils";
import { Button } from "antd";
import { Link } from "react-router-dom";
import { PublicKey } from "@solana/web3.js";
export const ReserveItem = (props: { reserve: LendingReserve }) => {
export const ReserveItem = (props: { reserve: LendingReserve, address: PublicKey }) => {
const name = useTokenName(props.reserve.liquidityMint);
const tokenBalance = useUserBalance(props.reserve.liquidityMint);
const collateralBalance = useUserBalance(props.reserve.collateralMint);
return <div style={{ display: 'flex', justifyContent: 'space-around' }}>
<TokenIcon mintAddress={props.reserve.liquidityMint} />
{name}
<span><TokenIcon mintAddress={props.reserve.liquidityMint} />{name}</span>
<div>{formatNumber.format(tokenBalance)} {name}</div>
<div>{formatNumber.format(collateralBalance)} {name}</div>
<Button >Deposit</Button>
<div>--</div>
<Link to={`/deposit/${props.address.toBase58()}`}>
<Button>
<span>Deposit</span>
</Button>
</Link>
</div>;
}

24
src/views/home/index.tsx Normal file
View File

@ -0,0 +1,24 @@
import React, { useMemo } from "react";
import { useLendingReserves, useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button } from "antd";
import { LendingReserveItem } from "./item";
export const HomeView = () => {
const { reserveAccounts } = useLendingReserves();
// TODO: add total Liquidity amount ...
return <div>
<div style={{ display: 'flex', justifyContent: 'space-around' }}>
<div>Asset</div>
<div>Market Size</div>
<div>Total Borrowed</div>
<div>Deposit APY</div>
<div>Borrow APY</div>
</div>
{reserveAccounts.map(account => <LendingReserveItem reserve={account.info} address={account.pubkey} />)}
</div>;
}

26
src/views/home/item.tsx Normal file
View File

@ -0,0 +1,26 @@
import React, { useMemo } from "react";
import { useTokenName, useUserAccounts, useUserBalance } from '../../hooks';
import { LendingReserve } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button, Card } from "antd";
import { Link } from "react-router-dom";
import { PublicKey } from "@solana/web3.js";
export const LendingReserveItem = (props: { reserve: LendingReserve, address: PublicKey }) => {
const name = useTokenName(props.reserve.liquidityMint);
const tokenBalance = useUserBalance(props.reserve.liquidityMint);
const collateralBalance = useUserBalance(props.reserve.collateralMint);
return <Card>
<Link to={`/reserve/${props.address.toBase58()}`}>
<div style={{ display: 'flex', justifyContent: 'space-around' }}>
<span><TokenIcon mintAddress={props.reserve.liquidityMint} />{name}</span>
<div>{formatNumber.format(tokenBalance)} {name}</div>
<div>{formatNumber.format(collateralBalance)} {name}</div>
<div>--</div>
</div>
</Link>
</Card>;
}

5
src/views/index.tsx Normal file
View File

@ -0,0 +1,5 @@
export { HomeView } from './home';
export { BorrowView } from './borrow';
export { DashboardView } from './dashboard';
export { DepositView, DepositAddView } from './deposit';
export { ReserveView } from './reserve';

View File

@ -0,0 +1,30 @@
import React, { useMemo } from "react";
import { useLendingReserve, useTokenName, useUserAccounts, useUserBalance } from './../../hooks';
import { LendingReserve, LendingReserveParser } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button } from "antd";
import { useParams } from "react-router-dom";
import { useAccount } from "../../contexts/accounts";
export const ReserveView = () => {
const { id } = useParams<{ id: string }>();
const lendingReserve = useLendingReserve(id);
const reserve = lendingReserve?.info;
const name = useTokenName(reserve?.liquidityMint);
const tokenBalance = useUserBalance(reserve?.liquidityMint);
const collateralBalance = useUserBalance(reserve?.collateralMint);
return <div style={{ display: 'flex', justifyContent: 'space-around' }}>
<TokenIcon mintAddress={reserve?.liquidityMint} />
{name}
<div>{formatNumber.format(tokenBalance)} {name}</div>
<div>{formatNumber.format(collateralBalance)} {name}</div>
<div>--</div>
<Button>Deposit</Button>
ADD: {id}
</div>;
}