188 lines
7.5 KiB
JavaScript
188 lines
7.5 KiB
JavaScript
import { ArrowBack } from "@mui/icons-material";
|
|
import { Box, Link, Skeleton, Typography } from "@mui/material";
|
|
import { useEffect, useState, useMemo, useCallback } from "react";
|
|
import { Link as RouterLink, useLocation, useParams, useNavigate } from "react-router-dom";
|
|
import { useAccount, useSwitchChain } from "wagmi";
|
|
import { isAddress } from "viem";
|
|
import ReactGA from "react-ga4";
|
|
|
|
import PageTitle from "../../components/PageTitle/PageTitle";
|
|
import Metric from "../../components/Metric/Metric";
|
|
import TokenStack from "../../components/TokenStack/TokenStack";
|
|
|
|
import BondPrice from "./components/BondPrice";
|
|
import BondDiscount from "./components/BondDiscount";
|
|
import BondInputArea from "./components/BondInputArea";
|
|
import BondSettingsModal from "./components/BondSettingsModal";
|
|
|
|
import NotFound from "../NotFound/NotFound";
|
|
|
|
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
|
import { isNetworkLegacy } from "../../constants";
|
|
import { formatCurrency } from "../../helpers";
|
|
|
|
import { useLocalStorage } from "../../hooks/localstorage";
|
|
import { useLiveBonds } from "../../hooks/bonds";
|
|
import { useFtsoPrice } from "../../hooks/prices";
|
|
|
|
const BondModalContainer = ({ chainId, address, config, connect }) => {
|
|
const { id, network } = useParams();
|
|
const { liveBonds } = useLiveBonds(chainId, network);
|
|
const bond = liveBonds.find(bond => bond.id === Number(id));
|
|
|
|
if (!bond) return <NotFound />;
|
|
|
|
return <BondModal config={config} chainId={chainId} bond={bond} address={address} connect={connect} />;
|
|
};
|
|
|
|
export const BondModal = ({ bond, chainId, address, config, connect }) => {
|
|
const navigate = useNavigate();
|
|
const { network } = useParams();
|
|
const { pathname } = useLocation();
|
|
|
|
const [isSettingsOpen, setSettingsOpen] = useState(false);
|
|
const { getStorageValue, setStorageValue } = useLocalStorage();
|
|
|
|
const [slippage, setSlippage] = useState(() => getStorageValue(chainId, address, "bond-slippage", "10"));
|
|
const [formatDecimals, setFormatDecimals] = useState(() => getStorageValue(chainId, address, "bond-decimals", "5"));
|
|
const [recipientAddress, setRecipientAddressInner] = useState(() => getStorageValue(chainId, address, "bond-recipient", address));
|
|
|
|
useEffect(() => {
|
|
ReactGA.send({ hitType: "pageview", page: pathname });
|
|
}, [])
|
|
|
|
const setRecipientAddress = useCallback((value) => {
|
|
setRecipientAddressInner(value);
|
|
if (isAddress(value)) {
|
|
setStorageValue(chainId, address, "bond-recipient", value);
|
|
}
|
|
}, [chainId, address]);
|
|
|
|
const setSlippageInner = useCallback((value) => {
|
|
const maybeValue = parseFloat(value);
|
|
if (!maybeValue || parseFloat(value) <= 100) {
|
|
setSlippage(value);
|
|
setStorageValue(chainId, address, "bond-slippage", value);
|
|
}
|
|
}, [chainId, address]);
|
|
|
|
const setFormatDecimalsInner = useCallback((value) => {
|
|
if (Number(value) <= 17) {
|
|
setFormatDecimals(value);
|
|
setStorageValue(chainId, address, "bond-decimals", value);
|
|
}
|
|
}, [chainId, address]);
|
|
|
|
useEffect(() => {
|
|
const handleKeyDown = (event) => {
|
|
if (event.key === "Escape") isSettingsOpen ? setSettingsOpen(false) : navigate(`/${network}/bonds`);
|
|
};
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
}, [network, navigate, isSettingsOpen]);
|
|
|
|
const chainSymbol = useMemo(() => {
|
|
const chainSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
|
|
if (chainSymbol) return chainSymbol;
|
|
return "WTF";
|
|
}, [config]);
|
|
|
|
const preparedQuoteToken = useMemo(() => {
|
|
if (isNetworkLegacy(chainId)) {
|
|
return {
|
|
address: bond.quoteToken.quoteTokenAddress,
|
|
icons: bond.quoteToken.icons,
|
|
name: bond.quoteToken.name,
|
|
}
|
|
}
|
|
return { address: undefined, icons: [chainSymbol], name: chainSymbol };
|
|
}, [bond, chainSymbol, chainId])
|
|
|
|
return (
|
|
<Box>
|
|
<PageTitle
|
|
name={
|
|
<Box display="flex" flexDirection="row" alignItems="center">
|
|
<Link component={RouterLink} to={`/${network}/bonds`}>
|
|
<Box display="flex" flexDirection="row">
|
|
<ArrowBack />
|
|
<Typography fontWeight="500" marginLeft="9.5px" marginRight="18px">
|
|
Back
|
|
</Typography>
|
|
</Box>
|
|
</Link>
|
|
|
|
<TokenStack tokens={preparedQuoteToken.icons} sx={{ fontSize: "27px" }} />
|
|
<Box display="flex" flexDirection="column" ml={1} justifyContent="center" alignItems="center">
|
|
<Typography variant="h4" fontWeight={500}>
|
|
{preparedQuoteToken.name}
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
}
|
|
/>
|
|
|
|
<Box display="flex" flexDirection="column" alignItems="center">
|
|
<BondSettingsModal
|
|
open={isSettingsOpen}
|
|
handleClose={() => setSettingsOpen(false)}
|
|
slippage={slippage}
|
|
recipientAddress={recipientAddress}
|
|
formatDecimals={formatDecimals}
|
|
onRecipientAddressChange={event => setRecipientAddress(event.currentTarget.value)}
|
|
onSlippageChange={event => setSlippageInner(event.currentTarget.value)}
|
|
onDecimalsChange={event => setFormatDecimalsInner(event.currentTarget.value)}
|
|
/>
|
|
|
|
<Box display="flex" flexDirection="row" justifyContent="space-between" width={["100%", "70%"]} mt="24px">
|
|
<Metric
|
|
label={`Bond Price`}
|
|
metric={
|
|
bond.isSoldOut ? (
|
|
"--"
|
|
) : (
|
|
<BondPrice
|
|
price={bond.price.inUsd}
|
|
/>
|
|
)
|
|
}
|
|
/>
|
|
<Metric
|
|
label="Market Price"
|
|
metric={<TokenPrice priceInUsd={bond.price.marketPriceInUsd} />}
|
|
/>
|
|
<Metric
|
|
label="Discount"
|
|
metric={<BondDiscount discount={bond.discount} textOnly />}
|
|
/>
|
|
</Box>
|
|
|
|
<Box width="100%" mt="24px">
|
|
<BondInputArea
|
|
chainId={chainId}
|
|
bond={bond}
|
|
config={config}
|
|
connect={connect}
|
|
address={address}
|
|
slippage={slippage}
|
|
recipientAddress={recipientAddress}
|
|
preparedQuoteToken={preparedQuoteToken}
|
|
handleSettingsOpen={() => setSettingsOpen(true)}
|
|
formatDecimals={formatDecimals}
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
const TokenPrice = ({ priceInUsd }) => {
|
|
return priceInUsd ? (
|
|
<>{formatCurrency(priceInUsd, 2)}</>
|
|
) : (
|
|
<Skeleton width={60} />
|
|
);
|
|
};
|
|
|
|
export default BondModalContainer;
|