ghost-dao-interface/src/containers/Bond/components/BondList.jsx
Uncle Fatso 7f0b59aa8c
fixes of representation for bond prices
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2025-05-12 19:10:32 +03:00

260 lines
8.8 KiB
JavaScript

import {
Box,
Link,
SvgIcon,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
useMediaQuery
} from "@mui/material";
import { NavLink } from "react-router-dom";
import ArrowUp from "../../../assets/icons/arrow-up.svg?react";
import BondDiscount from "./BondDiscount";
import BondDuration from "./BondDuration";
import BondInfoText from "./BondInfoText";
import BondPrice from "./BondPrice";
import { useScreenSize } from "../../../hooks/useScreenSize";
import { sortBondsByDiscount, formatNumber } from "../../../helpers";
import TokenStack from "../../../components/TokenStack/TokenStack";
import { TertiaryButton } from "../../../components/Button";
export const BondList = ({ bonds, secondsTo, chainId }) => {
const isSmallScreen = useScreenSize("md");
if (bonds.length === 0) {
return (
<Box display="flex" justifyContent="center">
<Typography variant="h4">No active bonds</Typography>
</Box>
);
}
if (isSmallScreen) {
return (
<>
<Box my="24px" textAlign="center">
<BondInfoText />
</Box>
{sortBondsByDiscount(bonds).map(bond => (
<BondCard key={bond.id} secondsTo={secondsTo} bond={bond} />
))}
</>
);
}
return (
<>
<BondTable>
{sortBondsByDiscount(bonds).map(bond => (
<BondRow key={bond.id} bond={bond} secondsTo={secondsTo} />
))}
</BondTable>
<Box mt="24px" textAlign="center" width="70%" mx="auto">
<BondInfoText />
</Box>
</>
);
};
const BondCard = ({ bond, secondsTo }) => {
const quoteTokenName = bond.quoteToken.name;
const baseTokenName = bond.baseToken.name;
return (
<Box key={bond.id} id={bond.id + `--bond`} mt="32px">
<Box display="flex" alignItems="center">
<TokenStack tokens={bond.quoteToken.icons} />
<Box display="flex" flexDirection="column" ml="8px">
<Typography>{bond.quoteToken.name}</Typography>
<Link href={bond.quoteToken.purchaseUrl} target="_blank" rel="noopener noreferrer">
<Box display="flex" alignItems="center">
<Typography>Get Asset</Typography>
<Box ml="4px">
<SvgIcon component={ArrowUp} />
</Box>
</Box>
</Link>
</Box>
</Box>
<Box display="flex" justifyContent="space-between" mt="16px">
<Typography>Price</Typography>
<Typography component={'span'}>
{bond.isSoldOut ? (
"--"
) : (
<BondPrice price={bond.price.inUsd} />
)}
</Typography>
</Box>
<Box display="flex" justifyContent="space-between" mt="8px">
<Typography>Discount</Typography>
<Typography component={'span'}>{
bond.isSoldOut
? "--"
: <BondDiscount discount={bond.discount} />
}</Typography>
</Box>
<Box display="flex" justifyContent="space-between" mt="8px">
<Typography>Max Payout</Typography>
<Typography>
{`${payoutTokenCapacity(bond)}${
bond.baseToken.name !== bond.quoteToken.name ? ` (${quoteTokenCapacity(bond)})` : ``
}`}
</Typography>
</Box>
<Box display="flex" justifyContent="space-between" mt="8px">
<Typography>Duration</Typography>
<Typography component={'span'}>
<BondDuration secondsTo={secondsTo} duration={bond.duration} />
</Typography>
</Box>
<Box mt="16px">
<Link
component={NavLink}
to={`/bonds/${bond.id}`}
>
<TertiaryButton fullWidth>
Bond
</TertiaryButton>
</Link>
</Box>
</Box>
);
};
const BondTable = ({ children }) => (
<TableContainer>
<Table aria-label="Available bonds" style={{ tableLayout: "fixed" }}>
<TableHead>
<TableRow>
<TableCell style={{ padding: "8px 0", width: "162px" }}>Bond</TableCell>
<TableCell style={{ padding: "8px 0", width: "146px" }}>Price</TableCell>
<TableCell style={{ padding: "8px 0", width: "92px" }}>Discount</TableCell>
<TableCell style={{ padding: "8px 0" }}>Max Payout</TableCell>
<TableCell style={{ padding: "8px 0" }}>Duration</TableCell>
</TableRow>
</TableHead>
<TableBody>{children}</TableBody>
</Table>
</TableContainer>
);
const quoteTokenCapacity = (bond) => {
const quoteTokenCapacity = bond.maxPayout.inQuoteToken.lt(bond.capacity.inQuoteToken)
? bond.maxPayout.inQuoteToken
: bond.capacity.inQuoteToken;
return `${formatNumber(quoteTokenCapacity, 4)} ${bond.quoteToken.name}`;
};
const payoutTokenCapacity = (bond) => {
const payoutTokenCapacity = bond.maxPayout.inBaseToken.lt(bond.capacity.inBaseToken)
? bond.maxPayout.inBaseToken
: bond.capacity.inBaseToken;
return `${formatNumber(payoutTokenCapacity, 4)} FTSO`;
};
const BondRow = ({ bond, secondsTo }) => {
const quoteTokenName = bond.quoteToken.name;
const baseTokenName = bond.baseToken.name;
return (
<TableRow id={bond.id + `--bond`} data-testid={bond.id + `--bond`}>
<TableCell style={{ padding: "8px 0" }}>
<TokenIcons token={bond.quoteToken} />
</TableCell>
<TableCell style={{ padding: "8px 0" }}>
<Typography>
{bond.isSoldOut ? (
"--"
) : (
<BondPrice price={bond.price.inUsd} />
)}
</Typography>
</TableCell>
<TableCell style={{ padding: "8px 0" }}>
<Typography component="div">
{bond.isSoldOut ? "--" : <BondDiscount discount={bond.discount} />}
</Typography>
</TableCell>
<TableCell style={{ padding: "8px 0" }}>
<Box display="flex" flexDirection={"column"}>
<Typography style={{ lineHeight: "20px" }}>{payoutTokenCapacity(bond)}</Typography>
{bond.baseToken.name !== bond.quoteToken.name && (
<Typography color="textSecondary" style={{ fontSize: "12px", fontWeight: 400, lineHeight: "18px" }}>
{quoteTokenCapacity(bond)}
</Typography>
)}
</Box>
</TableCell>
<TableCell style={{ padding: "8px 0" }}>
<Typography>{
bond.isSoldOut
? "--"
: <BondDuration secondsTo={secondsTo} duration={bond.duration} />
}</Typography>
</TableCell>
<TableCell style={{ padding: "8px 0" }}>
<Link
component={NavLink}
to={`/bonds/${bond.id}`}
>
<TertiaryButton fullWidth disabled={bond.isSoldOut}>
{bond.isSoldOut ? "Sold Out" : `Bond`}
</TertiaryButton>
</Link>
</TableCell>
</TableRow>
);
};
const TokenIcons = ({ token, chainId, explorer }) => (
<Box display="flex" alignItems="center">
<TokenStack tokens={token.icons} />
<Box display="flex" flexDirection="column" ml="16px">
<Typography style={{ fontSize: "12px", fontWeight: 600, lineHeight: "18px" }}>{token.name}</Typography>
<Link
color="primary"
target="_blank"
href={explorer ? `https://etherscan.io/token/${token.addresses[chainId]}` : token.purchaseUrl}
>
<Box display="flex" alignItems="center">
<Typography style={{ fontSize: "12px", lineHeight: "18px" }}>
{explorer ? `Explorer` : `Get Asset`}
</Typography>
<Box ml="4px">
<SvgIcon component={ArrowUp} />
</Box>
</Box>
</Link>
</Box>
</Box>
);