From 446eec29d7a3403dcfe17a4fc1b86679e90841e5 Mon Sep 17 00:00:00 2001 From: man0s <95379755+losman0s@users.noreply.github.com> Date: Thu, 7 Sep 2023 20:19:07 +0800 Subject: [PATCH 001/351] feat(mfi-v2-ui): bootstrap mobile components tree --- apps/marginfi-v2-ui/package.json | 1 + .../src/components/Navbar/index.tsx | 3 - .../{ => common}/useFirebaseAccount.tsx | 0 .../{ => common}/useWalletContext.tsx | 0 .../AccountSummary/AccountSummary.tsx | 2 +- .../AccountSummary/GlobalStats.tsx | 2 +- .../AccountSummary/UserStats.tsx | 2 +- .../{ => desktop}/AccountSummary/index.tsx | 0 .../AccountSummary/style.module.css | 0 .../AssetsList/AssetRow/AssetRow.tsx | 2 +- .../AssetsList/AssetRow/AssetRowAction.tsx | 0 .../AssetsList/AssetRow/AssetRowInputBox.tsx | 0 .../AssetsList/AssetRow/index.ts | 0 .../{ => desktop}/AssetsList/AssetsList.tsx | 2 +- .../AssetsList/BorrowLendToggle.tsx | 0 .../{ => desktop}/AssetsList/index.ts | 0 .../src/components/{ => desktop}/Banner.tsx | 0 .../{ => desktop}/CampaignWizard.tsx | 2 +- .../{ => desktop}/Countdown.module.css | 0 .../components/{ => desktop}/Countdown.tsx | 0 .../DesktopNavbar}/AirdropZone.module.css | 2 +- .../DesktopNavbar}/AirdropZone.tsx | 2 +- .../DesktopNavbar/DesktopNavbar.module.css} | 0 .../DesktopNavbar/DesktopNavbar.tsx} | 8 +- .../DesktopNavbar}/WalletButton.tsx | 2 +- .../desktop/DesktopNavbar/index.tsx | 3 + .../components/{ => desktop}/Earn/index.tsx | 6 +- .../{ => desktop}/Footer/Footer.tsx | 0 .../components/{ => desktop}/Footer/index.tsx | 0 .../{ => desktop}/OverlaySpinner.tsx | 0 .../components/{ => desktop}/PageHeader.tsx | 0 .../src/components/{ => desktop}/Tooltip.tsx | 0 .../UserPositionRow/UserPositionRow.tsx | 0 .../UserPositionRow/UserPositionRowAction.tsx | 0 .../UserPositionRowInputBox.tsx | 0 .../UserPositions/UserPositionRow/index.tsx | 0 .../UserPositions/UserPositions.tsx | 0 .../{ => desktop}/UserPositions/index.tsx | 0 apps/marginfi-v2-ui/src/components/index.tsx | 8 - .../DesktopNavbar/AirdropZone.module.css | 98 ++++++++++++ .../mobile/DesktopNavbar/AirdropZone.tsx | 150 ++++++++++++++++++ .../DesktopNavbar/MobileNavbar.module.css | 16 ++ .../mobile/DesktopNavbar/MobileNavbar.tsx | 76 +++++++++ .../mobile/DesktopNavbar/WalletButton.tsx | 22 +++ .../components/mobile/DesktopNavbar/index.tsx | 3 + apps/marginfi-v2-ui/src/mediaQueries.ts | 14 ++ apps/marginfi-v2-ui/src/pages/_app.tsx | 15 +- apps/marginfi-v2-ui/src/pages/bridge.tsx | 4 +- apps/marginfi-v2-ui/src/pages/earn.tsx | 2 +- apps/marginfi-v2-ui/src/pages/index.tsx | 21 ++- apps/marginfi-v2-ui/src/pages/lip.tsx | 6 +- apps/marginfi-v2-ui/src/pages/points.tsx | 6 +- apps/marginfi-v2-ui/src/pages/swap.tsx | 4 +- .../marginfi-v2-ui/src/pages/terms/points.tsx | 2 +- yarn.lock | 31 +++- 55 files changed, 466 insertions(+), 51 deletions(-) delete mode 100644 apps/marginfi-v2-ui/src/components/Navbar/index.tsx rename apps/marginfi-v2-ui/src/components/{ => common}/useFirebaseAccount.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => common}/useWalletContext.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AccountSummary/AccountSummary.tsx (94%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AccountSummary/GlobalStats.tsx (99%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AccountSummary/UserStats.tsx (99%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AccountSummary/index.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AccountSummary/style.module.css (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AssetsList/AssetRow/AssetRow.tsx (99%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AssetsList/AssetRow/AssetRowAction.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AssetsList/AssetRow/AssetRowInputBox.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AssetsList/AssetRow/index.ts (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AssetsList/AssetsList.tsx (99%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AssetsList/BorrowLendToggle.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/AssetsList/index.ts (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/Banner.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/CampaignWizard.tsx (99%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/Countdown.module.css (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/Countdown.tsx (100%) rename apps/marginfi-v2-ui/src/components/{Navbar => desktop/DesktopNavbar}/AirdropZone.module.css (96%) rename apps/marginfi-v2-ui/src/components/{Navbar => desktop/DesktopNavbar}/AirdropZone.tsx (98%) rename apps/marginfi-v2-ui/src/components/{Navbar/Navbar.module.css => desktop/DesktopNavbar/DesktopNavbar.module.css} (100%) rename apps/marginfi-v2-ui/src/components/{Navbar/Navbar.tsx => desktop/DesktopNavbar/DesktopNavbar.tsx} (97%) rename apps/marginfi-v2-ui/src/components/{Navbar => desktop/DesktopNavbar}/WalletButton.tsx (89%) create mode 100644 apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/index.tsx rename apps/marginfi-v2-ui/src/components/{ => desktop}/Earn/index.tsx (99%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/Footer/Footer.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/Footer/index.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/OverlaySpinner.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/PageHeader.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/Tooltip.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/UserPositions/UserPositionRow/UserPositionRow.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/UserPositions/UserPositionRow/UserPositionRowAction.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/UserPositions/UserPositionRow/UserPositionRowInputBox.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/UserPositions/UserPositionRow/index.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/UserPositions/UserPositions.tsx (100%) rename apps/marginfi-v2-ui/src/components/{ => desktop}/UserPositions/index.tsx (100%) delete mode 100644 apps/marginfi-v2-ui/src/components/index.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.module.css create mode 100644 apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.module.css create mode 100644 apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/index.tsx create mode 100644 apps/marginfi-v2-ui/src/mediaQueries.ts diff --git a/apps/marginfi-v2-ui/package.json b/apps/marginfi-v2-ui/package.json index 4f42be0b9b..3a7b702260 100644 --- a/apps/marginfi-v2-ui/package.json +++ b/apps/marginfi-v2-ui/package.json @@ -40,6 +40,7 @@ "react-hotkeys-hook": "^4.4.1", "react-katex": "^3.0.1", "react-number-format": "^5.2.2", + "react-responsive": "^9.0.2", "react-spinners": "^0.13.8", "react-toastify": "^9.1.1", "sharp": "^0.31.3", diff --git a/apps/marginfi-v2-ui/src/components/Navbar/index.tsx b/apps/marginfi-v2-ui/src/components/Navbar/index.tsx deleted file mode 100644 index 78d24d8447..0000000000 --- a/apps/marginfi-v2-ui/src/components/Navbar/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { Navbar } from "./Navbar"; - -export { Navbar }; diff --git a/apps/marginfi-v2-ui/src/components/useFirebaseAccount.tsx b/apps/marginfi-v2-ui/src/components/common/useFirebaseAccount.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/useFirebaseAccount.tsx rename to apps/marginfi-v2-ui/src/components/common/useFirebaseAccount.tsx diff --git a/apps/marginfi-v2-ui/src/components/useWalletContext.tsx b/apps/marginfi-v2-ui/src/components/common/useWalletContext.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/useWalletContext.tsx rename to apps/marginfi-v2-ui/src/components/common/useWalletContext.tsx diff --git a/apps/marginfi-v2-ui/src/components/AccountSummary/AccountSummary.tsx b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/AccountSummary.tsx similarity index 94% rename from apps/marginfi-v2-ui/src/components/AccountSummary/AccountSummary.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AccountSummary/AccountSummary.tsx index ade5b63e08..e8f06d0c79 100644 --- a/apps/marginfi-v2-ui/src/components/AccountSummary/AccountSummary.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/AccountSummary.tsx @@ -2,7 +2,7 @@ import React, { FC } from "react"; import { UserStats } from "./UserStats"; import { useMrgnlendStore } from "~/store"; import dynamic from "next/dynamic"; -import { useWalletContext } from "../useWalletContext"; +import { useWalletContext } from "../../common/useWalletContext"; const GlobalStats = dynamic(async () => (await import("./GlobalStats")).GlobalStats, { ssr: false }); diff --git a/apps/marginfi-v2-ui/src/components/AccountSummary/GlobalStats.tsx b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/GlobalStats.tsx similarity index 99% rename from apps/marginfi-v2-ui/src/components/AccountSummary/GlobalStats.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AccountSummary/GlobalStats.tsx index 3ee2b6c0a3..e34da6210c 100644 --- a/apps/marginfi-v2-ui/src/components/AccountSummary/GlobalStats.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/GlobalStats.tsx @@ -2,7 +2,7 @@ import { Typography, Skeleton } from "@mui/material"; import Image from "next/image"; import Link from "next/link"; import { FC } from "react"; -import { MrgnTooltip } from "~/components/Tooltip"; +import { MrgnTooltip } from "~/components/desktop/Tooltip"; import styles from "./style.module.css"; import { numeralFormatter } from "@mrgnlabs/mrgn-common"; diff --git a/apps/marginfi-v2-ui/src/components/AccountSummary/UserStats.tsx b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/UserStats.tsx similarity index 99% rename from apps/marginfi-v2-ui/src/components/AccountSummary/UserStats.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AccountSummary/UserStats.tsx index 73ff1d803f..1fe1c66882 100644 --- a/apps/marginfi-v2-ui/src/components/AccountSummary/UserStats.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/UserStats.tsx @@ -2,7 +2,7 @@ import { Typography, Skeleton } from "@mui/material"; import Image from "next/image"; import Link from "next/link"; import { FC, useMemo } from "react"; -import { MrgnTooltip } from "~/components/Tooltip"; +import { MrgnTooltip } from "~/components/desktop/Tooltip"; import React from "react"; import { AccountSummary } from "@mrgnlabs/marginfi-v2-ui-state"; import { usdFormatter, numeralFormatter, usdFormatterDyn, percentFormatter } from "@mrgnlabs/mrgn-common"; diff --git a/apps/marginfi-v2-ui/src/components/AccountSummary/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/index.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/AccountSummary/index.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AccountSummary/index.tsx diff --git a/apps/marginfi-v2-ui/src/components/AccountSummary/style.module.css b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/style.module.css similarity index 100% rename from apps/marginfi-v2-ui/src/components/AccountSummary/style.module.css rename to apps/marginfi-v2-ui/src/components/desktop/AccountSummary/style.module.css diff --git a/apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/AssetRow.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx similarity index 99% rename from apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/AssetRow.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx index d2c5ff5078..828a4da588 100644 --- a/apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/AssetRow.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx @@ -27,7 +27,7 @@ import { ExtendedBankMetadata, } from "@mrgnlabs/marginfi-v2-ui-state"; import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2"; -import { useWalletContext } from "~/components/useWalletContext"; +import { useWalletContext } from "~/components/common/useWalletContext"; const CLOSE_BALANCE_TOAST_ID = "close-balance"; const BORROW_OR_LEND_TOAST_ID = "borrow-or-lend"; diff --git a/apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/AssetRowAction.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowAction.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/AssetRowAction.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowAction.tsx diff --git a/apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/AssetRowInputBox.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowInputBox.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/AssetRowInputBox.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowInputBox.tsx diff --git a/apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/index.ts b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/index.ts similarity index 100% rename from apps/marginfi-v2-ui/src/components/AssetsList/AssetRow/index.ts rename to apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/index.ts diff --git a/apps/marginfi-v2-ui/src/components/AssetsList/AssetsList.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx similarity index 99% rename from apps/marginfi-v2-ui/src/components/AssetsList/AssetsList.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx index 051d270f71..244fdc86cd 100644 --- a/apps/marginfi-v2-ui/src/components/AssetsList/AssetsList.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx @@ -9,7 +9,7 @@ import AssetRow from "./AssetRow"; import { useMrgnlendStore, useUserProfileStore } from "~/store"; import { useHotkeys } from "react-hotkeys-hook"; import { LoadingAsset } from "./AssetRow/AssetRow"; -import { useWalletContext } from "../useWalletContext"; +import { useWalletContext } from "../../common/useWalletContext"; const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( diff --git a/apps/marginfi-v2-ui/src/components/AssetsList/BorrowLendToggle.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/BorrowLendToggle.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/AssetsList/BorrowLendToggle.tsx rename to apps/marginfi-v2-ui/src/components/desktop/AssetsList/BorrowLendToggle.tsx diff --git a/apps/marginfi-v2-ui/src/components/AssetsList/index.ts b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/index.ts similarity index 100% rename from apps/marginfi-v2-ui/src/components/AssetsList/index.ts rename to apps/marginfi-v2-ui/src/components/desktop/AssetsList/index.ts diff --git a/apps/marginfi-v2-ui/src/components/Banner.tsx b/apps/marginfi-v2-ui/src/components/desktop/Banner.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/Banner.tsx rename to apps/marginfi-v2-ui/src/components/desktop/Banner.tsx diff --git a/apps/marginfi-v2-ui/src/components/CampaignWizard.tsx b/apps/marginfi-v2-ui/src/components/desktop/CampaignWizard.tsx similarity index 99% rename from apps/marginfi-v2-ui/src/components/CampaignWizard.tsx rename to apps/marginfi-v2-ui/src/components/desktop/CampaignWizard.tsx index ee3cc497d7..6c2747e447 100644 --- a/apps/marginfi-v2-ui/src/components/CampaignWizard.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/CampaignWizard.tsx @@ -20,7 +20,7 @@ import { NumberFormatValues, NumericFormat } from "react-number-format"; import { useMrgnlendStore } from "~/store"; import { computeGuaranteedApy } from "@mrgnlabs/lip-client"; import { EarnAction } from "./Earn"; -import { useWalletContext } from "./useWalletContext"; +import { useWalletContext } from "~/components/common/useWalletContext"; interface CampaignWizardInputBox { value: number; diff --git a/apps/marginfi-v2-ui/src/components/Countdown.module.css b/apps/marginfi-v2-ui/src/components/desktop/Countdown.module.css similarity index 100% rename from apps/marginfi-v2-ui/src/components/Countdown.module.css rename to apps/marginfi-v2-ui/src/components/desktop/Countdown.module.css diff --git a/apps/marginfi-v2-ui/src/components/Countdown.tsx b/apps/marginfi-v2-ui/src/components/desktop/Countdown.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/Countdown.tsx rename to apps/marginfi-v2-ui/src/components/desktop/Countdown.tsx diff --git a/apps/marginfi-v2-ui/src/components/Navbar/AirdropZone.module.css b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.module.css similarity index 96% rename from apps/marginfi-v2-ui/src/components/Navbar/AirdropZone.module.css rename to apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.module.css index 93349b375c..ec66d7dcfa 100644 --- a/apps/marginfi-v2-ui/src/components/Navbar/AirdropZone.module.css +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.module.css @@ -16,7 +16,7 @@ #overlay { width: 100%; height: 100%; - background-image: url(../../../public/WaveBG2.png); + background-image: url(../../../../public/WaveBG2.png); background-size: 444px; padding: 20px 30px; background-repeat: no-repeat; diff --git a/apps/marginfi-v2-ui/src/components/Navbar/AirdropZone.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.tsx similarity index 98% rename from apps/marginfi-v2-ui/src/components/Navbar/AirdropZone.tsx rename to apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.tsx index 56e97ce843..a496b30197 100644 --- a/apps/marginfi-v2-ui/src/components/Navbar/AirdropZone.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.tsx @@ -10,7 +10,7 @@ import { getAssociatedTokenAddressSync, shortenAddress, } from "@mrgnlabs/mrgn-common"; -import { useWalletContext } from "../useWalletContext"; +import { useWalletContext } from "../../common/useWalletContext"; const SOL_AMOUNT = 2 * 10 ** 9; diff --git a/apps/marginfi-v2-ui/src/components/Navbar/Navbar.module.css b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.module.css similarity index 100% rename from apps/marginfi-v2-ui/src/components/Navbar/Navbar.module.css rename to apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.module.css diff --git a/apps/marginfi-v2-ui/src/components/Navbar/Navbar.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx similarity index 97% rename from apps/marginfi-v2-ui/src/components/Navbar/Navbar.tsx rename to apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx index 093a7a21ab..a24713530a 100644 --- a/apps/marginfi-v2-ui/src/components/Navbar/Navbar.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx @@ -10,12 +10,12 @@ import { useMrgnlendStore, useUserProfileStore } from "~/store"; import { useRouter } from "next/router"; import { HotkeysEvent } from "react-hotkeys-hook/dist/types"; import { Badge } from "@mui/material"; -import { useFirebaseAccount } from "../useFirebaseAccount"; +import { useFirebaseAccount } from "../../common/useFirebaseAccount"; import { groupedNumberFormatterDyn, numeralFormatter } from "@mrgnlabs/mrgn-common"; -import { useWalletContext } from "../useWalletContext"; +import { useWalletContext } from "../../common/useWalletContext"; // @todo implement second pretty navbar row -const Navbar: FC = () => { +const DesktopNavbar: FC = () => { useFirebaseAccount(); const { connected, walletAddress } = useWalletContext(); @@ -250,4 +250,4 @@ const Navbar: FC = () => { ); }; -export { Navbar }; +export { DesktopNavbar }; diff --git a/apps/marginfi-v2-ui/src/components/Navbar/WalletButton.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx similarity index 89% rename from apps/marginfi-v2-ui/src/components/Navbar/WalletButton.tsx rename to apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx index dfbd690866..5e0cd4ee7e 100644 --- a/apps/marginfi-v2-ui/src/components/Navbar/WalletButton.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx @@ -1,6 +1,6 @@ import dynamic from "next/dynamic"; import { FC } from "react"; -import { useWalletContext } from "../useWalletContext"; +import { useWalletContext } from "../../common/useWalletContext"; const WalletMultiButtonDynamic = dynamic( async () => (await import("@solana/wallet-adapter-react-ui")).WalletMultiButton, diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/index.tsx new file mode 100644 index 0000000000..5980855102 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/index.tsx @@ -0,0 +1,3 @@ +import { DesktopNavbar } from "./DesktopNavbar"; + +export { DesktopNavbar }; diff --git a/apps/marginfi-v2-ui/src/components/Earn/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/Earn/index.tsx similarity index 99% rename from apps/marginfi-v2-ui/src/components/Earn/index.tsx rename to apps/marginfi-v2-ui/src/components/desktop/Earn/index.tsx index 6d80b532f9..2b0760c16c 100644 --- a/apps/marginfi-v2-ui/src/components/Earn/index.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/Earn/index.tsx @@ -1,6 +1,6 @@ import React, { FC, MouseEventHandler, ReactNode, useCallback, useEffect, useMemo, useState } from "react"; import { useConnection, useWallet } from "@solana/wallet-adapter-react"; -import { PageHeader } from "~/components/PageHeader"; +import { PageHeader } from "~/components/desktop/PageHeader"; import { useLipClient } from "~/context"; import Button from "@mui/material/Button"; import Card from "@mui/material/Card"; @@ -28,10 +28,10 @@ import { usdFormatterDyn, } from "@mrgnlabs/mrgn-common"; import { Bank, PriceBias } from "@mrgnlabs/marginfi-client-v2"; -import { Countdown } from "~/components/Countdown"; +import { Countdown } from "~/components/desktop/Countdown"; import { toast } from "react-toastify"; import BigNumber from "bignumber.js"; -import { useWalletContext } from "~/components/useWalletContext"; +import { useWalletContext } from "~/components/common/useWalletContext"; import { useMrgnlendStore } from "~/store"; const Earn = () => { diff --git a/apps/marginfi-v2-ui/src/components/Footer/Footer.tsx b/apps/marginfi-v2-ui/src/components/desktop/Footer/Footer.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/Footer/Footer.tsx rename to apps/marginfi-v2-ui/src/components/desktop/Footer/Footer.tsx diff --git a/apps/marginfi-v2-ui/src/components/Footer/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/Footer/index.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/Footer/index.tsx rename to apps/marginfi-v2-ui/src/components/desktop/Footer/index.tsx diff --git a/apps/marginfi-v2-ui/src/components/OverlaySpinner.tsx b/apps/marginfi-v2-ui/src/components/desktop/OverlaySpinner.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/OverlaySpinner.tsx rename to apps/marginfi-v2-ui/src/components/desktop/OverlaySpinner.tsx diff --git a/apps/marginfi-v2-ui/src/components/PageHeader.tsx b/apps/marginfi-v2-ui/src/components/desktop/PageHeader.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/PageHeader.tsx rename to apps/marginfi-v2-ui/src/components/desktop/PageHeader.tsx diff --git a/apps/marginfi-v2-ui/src/components/Tooltip.tsx b/apps/marginfi-v2-ui/src/components/desktop/Tooltip.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/Tooltip.tsx rename to apps/marginfi-v2-ui/src/components/desktop/Tooltip.tsx diff --git a/apps/marginfi-v2-ui/src/components/UserPositions/UserPositionRow/UserPositionRow.tsx b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositionRow/UserPositionRow.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/UserPositions/UserPositionRow/UserPositionRow.tsx rename to apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositionRow/UserPositionRow.tsx diff --git a/apps/marginfi-v2-ui/src/components/UserPositions/UserPositionRow/UserPositionRowAction.tsx b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositionRow/UserPositionRowAction.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/UserPositions/UserPositionRow/UserPositionRowAction.tsx rename to apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositionRow/UserPositionRowAction.tsx diff --git a/apps/marginfi-v2-ui/src/components/UserPositions/UserPositionRow/UserPositionRowInputBox.tsx b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositionRow/UserPositionRowInputBox.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/UserPositions/UserPositionRow/UserPositionRowInputBox.tsx rename to apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositionRow/UserPositionRowInputBox.tsx diff --git a/apps/marginfi-v2-ui/src/components/UserPositions/UserPositionRow/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositionRow/index.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/UserPositions/UserPositionRow/index.tsx rename to apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositionRow/index.tsx diff --git a/apps/marginfi-v2-ui/src/components/UserPositions/UserPositions.tsx b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/UserPositions/UserPositions.tsx rename to apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx diff --git a/apps/marginfi-v2-ui/src/components/UserPositions/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/index.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/UserPositions/index.tsx rename to apps/marginfi-v2-ui/src/components/desktop/UserPositions/index.tsx diff --git a/apps/marginfi-v2-ui/src/components/index.tsx b/apps/marginfi-v2-ui/src/components/index.tsx deleted file mode 100644 index 0dfa370c12..0000000000 --- a/apps/marginfi-v2-ui/src/components/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { Navbar } from "./Navbar"; -import { Footer } from "./Footer"; -import { AccountSummary } from "./AccountSummary"; -import { AssetsList } from "./AssetsList"; -import { UserPositions } from "./UserPositions"; -import { Banner } from "./Banner"; - -export { Navbar, Footer, AccountSummary, AssetsList, UserPositions, Banner }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.module.css b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.module.css new file mode 100644 index 0000000000..ec66d7dcfa --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.module.css @@ -0,0 +1,98 @@ +#container { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: linear-gradient(180deg, #101416 0%, #080a0b 95.03%); + border-radius: 25px; + width: 40%; + max-width: 400px; + border: 2px solid #000; + font-family: "Aeonik Pro"; + font-weight: 300; + font-size: 18px; +} + +#overlay { + width: 100%; + height: 100%; + background-image: url(../../../../public/WaveBG2.png); + background-size: 444px; + padding: 20px 30px; + background-repeat: no-repeat; + background-position: right; + display: flex; + flex-direction: column; + align-items: center; +} + +#title { + margin: 0; + font-size: 25px; + width: 100%; + display: flex; + justify-content: center; +} + +#description { + width: 100%; + margin-top: 40px; + display: flex; + gap: 5px; + flex-direction: column; + text-align: center; + justify-content: space-between; + font-weight: 200; +} + +#table { + width: 60%; + margin: 0; + justify-content: center; + justify-content: space-between; + font-weight: 300; + line-height: 25px; +} + +.table-cell { + width: 100%; + padding-left: 0; + justify-content: center; +} + +#special-row { + width: 90%; + margin-top: 30px; + display: flex; + flex-direction: row; + justify-content: center; + gap: 10px; +} + +#second-row { + margin-top: 10px; + width: 100%; + display: flex; + flex-direction: row; + gap: 15px; +} + +#link-text { + margin-top: 50px; + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; +} + +#copy-link { + margin-top: 30px; + width: 100%; + display: flex; + justify-content: center; + gap: 20px; +} + +.action-button-disabled { + background-color: #6d6d6d !important; +} diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx new file mode 100644 index 0000000000..a496b30197 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx @@ -0,0 +1,150 @@ +import { Button, Modal } from "@mui/material"; +import { FC, useCallback, useState } from "react"; +import styles from "./AirdropZone.module.css"; +import { PublicKey, Transaction } from "@solana/web3.js"; +import { useConnection, useWallet } from "@solana/wallet-adapter-react"; +import { makeAirdropCollateralIx } from "~/utils"; +import { toast } from "react-toastify"; +import { + createAssociatedTokenAccountInstruction, + getAssociatedTokenAddressSync, + shortenAddress, +} from "@mrgnlabs/mrgn-common"; +import { useWalletContext } from "../../common/useWalletContext"; + +const SOL_AMOUNT = 2 * 10 ** 9; + +const NOTSOL_AMOUNT = 10 * 10 ** 9; +const NOTSOL_MINT = new PublicKey("4Bn9Wn1sgaD5KfMRZjxwKFcrUy6NKdyqLPtzddazYc4x"); +const NOTSOL_FAUCET = new PublicKey("tRqMXrkJysM78qhriPH8GmKza75e2ikqWSDwa3soxuB"); + +const USDC_AMOUNT = 10 * 10 ** 6; +const USDC_MINT = new PublicKey("F9jRT1xL7PCRepBuey5cQG5vWHFSbnvdWxJWKqtzMDsd"); +const USDC_FAUCET = new PublicKey("3ThaREisq3etoy9cvdzRgKypHsa8iTjMxj19AjETA1Fy"); + +const AirdropZone: FC = () => { + const [isOpen, setIsOpen] = useState(false); + const { walletAddress, walletContextState } = useWalletContext(); + const { connection } = useConnection(); + + const open = useCallback(async () => setIsOpen(true), []); + const close = useCallback(async () => setIsOpen(false), []); + + const airdropToken = useCallback( + async (amount: number, mint: PublicKey, faucet: PublicKey) => { + if (faucet && walletAddress) { + const ataAddress = getAssociatedTokenAddressSync(mint, walletAddress!); + const ixs = []; + const solBalance = await connection.getBalance(walletAddress); + if (solBalance < 0.05) { + await connection.requestAirdrop(walletAddress, 100000000); + } + const ataAi = await connection.getAccountInfo(ataAddress); + if (!ataAi) { + ixs.push(createAssociatedTokenAccountInstruction(walletAddress, ataAddress, walletAddress, mint)); + } + ixs.push(makeAirdropCollateralIx(amount, mint, ataAddress, faucet)); + + const tx = new Transaction(); + tx.add(...ixs); + + await walletContextState.sendTransaction(tx, connection, { + skipPreflight: true, + }); + } + }, + [connection, walletAddress, walletContextState] + ); + + if (!walletAddress) return null; + + return ( +
+ + Airdrop + + +
+
+

💰 Airdrop Zone 💰

+ + + +
+
+
+
+ ); +}; + +export default AirdropZone; diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.module.css b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.module.css new file mode 100644 index 0000000000..41065f1898 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.module.css @@ -0,0 +1,16 @@ +.airdrop-button { + background-color: rgba(21, 255, 0, 0.3) !important; + color: #c0c0c0 !important; + border: 1px solid #c0c0c0 !important; + padding: 0 10px !important; + height: 38px !important; + border-radius: 100px !important; +} + +.airdrop-button:hover { + font-weight: bold; + background-color: transparent; + color: white; + border: 1px solid white; + border-radius: 100px; +} diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx new file mode 100644 index 0000000000..5269b30ee6 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx @@ -0,0 +1,76 @@ +import { FC, useEffect } from "react"; +import Link from "next/link"; +import Image from "next/image"; +import AirdropZone from "./AirdropZone"; +import { useUserProfileStore } from "~/store"; +import { useRouter } from "next/router"; +import { useFirebaseAccount } from "../../common/useFirebaseAccount"; +import { useWalletContext } from "../../common/useWalletContext"; + +// @todo implement second pretty navbar row +const MobileNavbar: FC = () => { + useFirebaseAccount(); + + const { connected, walletAddress } = useWalletContext(); + const router = useRouter(); + const [fetchPoints] = useUserProfileStore((state) => [state.fetchPoints]); + + useEffect(() => { + if (!walletAddress) return; + fetchPoints(walletAddress.toBase58()).catch(console.error); + }, [fetchPoints, walletAddress]); + + return ( +
+ +
+ ); +}; + +export { MobileNavbar }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx new file mode 100644 index 0000000000..4959bdf3d1 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx @@ -0,0 +1,22 @@ +import dynamic from "next/dynamic"; +import { FC } from "react"; +import { useWalletContext } from "~/components/common/useWalletContext"; + +const WalletMultiButtonDynamic = dynamic( + async () => (await import("@solana/wallet-adapter-react-ui")).WalletMultiButton, + { ssr: false } +); + +const WalletButton: FC = () => { + const { connected } = useWalletContext(); + + return ( +
+ + {!connected &&
CONNECT
} +
+
+ ); +}; + +export { WalletButton }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/index.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/index.tsx new file mode 100644 index 0000000000..928ef3dc1b --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/index.tsx @@ -0,0 +1,3 @@ +import { MobileNavbar } from "./MobileNavbar"; + +export { MobileNavbar }; diff --git a/apps/marginfi-v2-ui/src/mediaQueries.ts b/apps/marginfi-v2-ui/src/mediaQueries.ts new file mode 100644 index 0000000000..da2f24058a --- /dev/null +++ b/apps/marginfi-v2-ui/src/mediaQueries.ts @@ -0,0 +1,14 @@ +import { FC } from 'react'; +import { useMediaQuery } from 'react-responsive'; + +const Desktop: FC<{children: any}> = ({ children }) => { + const isDesktop = useMediaQuery({ minWidth: 992 }); + return isDesktop ? children : null; +}; + +const Mobile: FC<{children: any}> = ({ children }) => { + const isMobile = useMediaQuery({ maxWidth: 992 }); + return isMobile ? children : null; +}; + +export { Desktop, Mobile }; diff --git a/apps/marginfi-v2-ui/src/pages/_app.tsx b/apps/marginfi-v2-ui/src/pages/_app.tsx index cc97a8f461..ac0fcccf6f 100644 --- a/apps/marginfi-v2-ui/src/pages/_app.tsx +++ b/apps/marginfi-v2-ui/src/pages/_app.tsx @@ -18,6 +18,9 @@ import "react-toastify/dist/ReactToastify.min.css"; import { ToastContainer } from "react-toastify"; import { Analytics } from "@vercel/analytics/react"; import dynamic from "next/dynamic"; +import { Desk } from "@mui/icons-material"; +import { Desktop, Mobile } from "~/mediaQueries"; +import { MobileNavbar } from "~/components/mobile/DesktopNavbar"; // Use require instead of import since order matters require("@solana/wallet-adapter-react-ui/styles.css"); @@ -25,8 +28,8 @@ require("~/styles/globals.css"); require("~/styles/fonts.css"); require("~/styles/asset-borders.css"); -const Navbar = dynamic(async () => (await import("~/components/Navbar")).Navbar, { ssr: false }); -const Footer = dynamic(async () => (await import("~/components/Footer")).Footer, { ssr: false }); +const DesktopNavbar = dynamic(async () => (await import("~/components/desktop/DesktopNavbar")).DesktopNavbar, { ssr: false }); +const Footer = dynamic(async () => (await import("~/components/desktop/Footer")).Footer, { ssr: false }); // Matomo const MATOMO_URL = "https://mrgn.matomo.cloud"; @@ -63,7 +66,13 @@ const MyApp = ({ Component, pageProps }: AppProps) => { - + + + + + + +
diff --git a/apps/marginfi-v2-ui/src/pages/bridge.tsx b/apps/marginfi-v2-ui/src/pages/bridge.tsx index 3614d52579..ef0b695dd7 100644 --- a/apps/marginfi-v2-ui/src/pages/bridge.tsx +++ b/apps/marginfi-v2-ui/src/pages/bridge.tsx @@ -5,10 +5,10 @@ import config from "~/config"; import Script from "next/script"; import { toast } from "react-toastify"; import { useHotkeys } from "react-hotkeys-hook"; -import { PageHeaderBridge } from "~/components/PageHeader"; +import { PageHeaderBridge } from "~/components/desktop/PageHeader"; import { MayanWidgetColors, MayanWidgetConfigType } from "~/types"; import { useUserProfileStore } from "~/store"; -import { useWalletContext } from "~/components/useWalletContext"; +import { useWalletContext } from "~/components/common/useWalletContext"; const tokens = [ "0x0000000000000000000000000000000000000000", // SOL diff --git a/apps/marginfi-v2-ui/src/pages/earn.tsx b/apps/marginfi-v2-ui/src/pages/earn.tsx index a5ed12e3fb..23ed704801 100644 --- a/apps/marginfi-v2-ui/src/pages/earn.tsx +++ b/apps/marginfi-v2-ui/src/pages/earn.tsx @@ -2,7 +2,7 @@ import dynamic from "next/dynamic"; import React from "react"; import { LipClientProvider } from "~/context"; -const Earn = dynamic(async () => (await import("~/components/Earn")).Earn, { ssr: false }); +const Earn = dynamic(async () => (await import("~/components/desktop/Earn")).Earn, { ssr: false }); const EarnPage = () => { return ( diff --git a/apps/marginfi-v2-ui/src/pages/index.tsx b/apps/marginfi-v2-ui/src/pages/index.tsx index 2817a13d78..a437b76e88 100644 --- a/apps/marginfi-v2-ui/src/pages/index.tsx +++ b/apps/marginfi-v2-ui/src/pages/index.tsx @@ -1,19 +1,20 @@ import React, { useEffect } from "react"; -import { Banner } from "~/components"; -import { PageHeader } from "~/components/PageHeader"; -import { useWalletContext } from "~/components/useWalletContext"; +import { Banner } from "~/components/desktop/Banner"; +import { PageHeader } from "~/components/desktop/PageHeader"; +import { useWalletContext } from "~/components/common/useWalletContext"; import { shortenAddress } from "@mrgnlabs/mrgn-common"; import config from "~/config/marginfi"; import { useMrgnlendStore } from "../store"; import dynamic from "next/dynamic"; -import { OverlaySpinner } from "~/components/OverlaySpinner"; +import { OverlaySpinner } from "~/components/desktop/OverlaySpinner"; import { useConnection } from "@solana/wallet-adapter-react"; +import { Desktop, Mobile } from "~/mediaQueries"; -const AccountSummary = dynamic(async () => (await import("~/components/AccountSummary")).AccountSummary, { +const AccountSummary = dynamic(async () => (await import("~/components/desktop/AccountSummary")).AccountSummary, { ssr: false, }); -const AssetsList = dynamic(async () => (await import("~/components/AssetsList")).AssetsList, { ssr: false }); -const UserPositions = dynamic(async () => (await import("~/components/UserPositions")).UserPositions, { ssr: false }); +const AssetsList = dynamic(async () => (await import("~/components/desktop/AssetsList")).AssetsList, { ssr: false }); +const UserPositions = dynamic(async () => (await import("~/components/desktop/UserPositions")).UserPositions, { ssr: false }); const Home = () => { const { walletAddress, wallet, isOverride } = useWalletContext(); @@ -59,6 +60,7 @@ const Home = () => { return ( <> +
{walletAddress && selectedAccount && isOverride && ( @@ -80,6 +82,11 @@ const Home = () => { {walletAddress && }
+
+ + + LETS GOOOOO + ); }; diff --git a/apps/marginfi-v2-ui/src/pages/lip.tsx b/apps/marginfi-v2-ui/src/pages/lip.tsx index 85dd283c6a..5fe2c348ff 100644 --- a/apps/marginfi-v2-ui/src/pages/lip.tsx +++ b/apps/marginfi-v2-ui/src/pages/lip.tsx @@ -1,7 +1,7 @@ -import { PageHeader } from "~/components/PageHeader"; -import { CampaignWizard } from "~/components/CampaignWizard"; +import { PageHeader } from "~/components/desktop/PageHeader"; +import { CampaignWizard } from "~/components/desktop/CampaignWizard"; import { LipClientProvider } from "~/context"; -import { useWalletContext } from "~/components/useWalletContext"; +import { useWalletContext } from "~/components/common/useWalletContext"; const LIP = () => { const { connected } = useWalletContext(); diff --git a/apps/marginfi-v2-ui/src/pages/points.tsx b/apps/marginfi-v2-ui/src/pages/points.tsx index d9a5552134..542bb9cb35 100644 --- a/apps/marginfi-v2-ui/src/pages/points.tsx +++ b/apps/marginfi-v2-ui/src/pages/points.tsx @@ -18,20 +18,20 @@ import { } from "@mui/material"; import { useConnection } from "@solana/wallet-adapter-react"; import { FC, useEffect, useState } from "react"; -import { PageHeader } from "~/components/PageHeader"; +import { PageHeader } from "~/components/desktop/PageHeader"; import FileCopyIcon from "@mui/icons-material/FileCopy"; import Link from "next/link"; import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; import { styled } from "@mui/material/styles"; import Image from "next/image"; import { useRouter } from "next/router"; -import { WalletButton } from "~/components/Navbar/WalletButton"; +import { WalletButton } from "~/components/desktop/DesktopNavbar/WalletButton"; import { grey } from "@mui/material/colors"; import { toast } from "react-toastify"; import { useUserProfileStore } from "~/store"; import { LeaderboardRow, fetchLeaderboardData, firebaseApi } from "@mrgnlabs/marginfi-v2-ui-state"; import { numeralFormatter, groupedNumberFormatterDyn } from "@mrgnlabs/mrgn-common"; -import { useWalletContext } from "~/components/useWalletContext"; +import { useWalletContext } from "~/components/common/useWalletContext"; const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( diff --git a/apps/marginfi-v2-ui/src/pages/swap.tsx b/apps/marginfi-v2-ui/src/pages/swap.tsx index 3ac0f5ee7a..6c0b12455e 100644 --- a/apps/marginfi-v2-ui/src/pages/swap.tsx +++ b/apps/marginfi-v2-ui/src/pages/swap.tsx @@ -2,8 +2,8 @@ import { useEffect } from "react"; import config from "~/config"; -import { PageHeaderSwap } from "~/components/PageHeader"; -import { useWalletContext } from "~/components/useWalletContext"; +import { PageHeaderSwap } from "~/components/desktop/PageHeader"; +import { useWalletContext } from "~/components/common/useWalletContext"; const SwapPage = () => { const { walletContextState } = useWalletContext(); diff --git a/apps/marginfi-v2-ui/src/pages/terms/points.tsx b/apps/marginfi-v2-ui/src/pages/terms/points.tsx index 4d80151738..9a8bf555d3 100644 --- a/apps/marginfi-v2-ui/src/pages/terms/points.tsx +++ b/apps/marginfi-v2-ui/src/pages/terms/points.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { PageHeader } from "~/components/PageHeader"; +import { PageHeader } from "~/components/desktop/PageHeader"; function Disclaimer() { return ( diff --git a/yarn.lock b/yarn.lock index 5e1d91c896..e79dc8ecd8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10653,6 +10653,11 @@ css-loader@^6.5.1: postcss-value-parser "^4.2.0" semver "^7.3.8" +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + integrity sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q== + css-minimizer-webpack-plugin@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz#ab78f781ced9181992fe7b6e4f3422e76429878f" @@ -14058,7 +14063,7 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -hyphenate-style-name@^1.0.3: +hyphenate-style-name@^1.0.0, hyphenate-style-name@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== @@ -16255,6 +16260,13 @@ marked@^4.0.10, marked@^4.0.16, marked@^4.2.12: resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== +matchmediaquery@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.3.1.tgz#8247edc47e499ebb7c58f62a9ff9ccf5b815c6d7" + integrity sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ== + dependencies: + css-mediaquery "^0.1.2" + md5-file@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-3.2.3.tgz#f9bceb941eca2214a4c0727f5e700314e770f06f" @@ -18528,7 +18540,7 @@ prompts@^2.0.1, prompts@^2.3.2, prompts@^2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@*, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@*, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -19109,6 +19121,16 @@ react-refresh@^0.4.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.4.3.tgz#966f1750c191672e76e16c2efa569150cc73ab53" integrity sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA== +react-responsive@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-9.0.2.tgz#34531ca77a61e7a8775714016d21241df7e4205c" + integrity sha512-+4CCab7z8G8glgJoRjAwocsgsv6VA2w7JPxFWHRc7kvz8mec1/K5LutNC2MG28Mn8mu6+bu04XZxHv5gyfT7xQ== + dependencies: + hyphenate-style-name "^1.0.0" + matchmediaquery "^0.3.0" + prop-types "^15.6.1" + shallow-equal "^1.2.1" + react-shallow-renderer@^16.15.0: version "16.15.0" resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457" @@ -19958,6 +19980,11 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" +shallow-equal@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da" + integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA== + sharp@^0.31.3: version "0.31.3" resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.31.3.tgz#60227edc5c2be90e7378a210466c99aefcf32688" From 5802a37b948f1d809f573462fbfcc8dfa5f15dc1 Mon Sep 17 00:00:00 2001 From: Kobe Leenders Date: Thu, 7 Sep 2023 23:44:27 +0200 Subject: [PATCH 002/351] WIP: mobile desktop overhaul - Desktop component restructuring - Component logic seperation - Mobile global stats - Hook logic - Mobile asset cards WIP --- .../common/AccountSummary/GlobalStats.tsx | 179 +++++++++ .../AccountSummary/UserStats.tsx | 9 +- .../components/common/AccountSummary/index.ts | 2 + .../AccountSummary/style.module.css | 2 +- .../AssetList}/BorrowLendToggle.tsx | 0 .../src/components/common/AssetList/index.ts | 1 + .../src/components/common/HtmlTooltip.tsx | 15 + .../desktop/AccountSummary/GlobalStats.tsx | 180 ---------- .../desktop/AccountSummary/index.tsx | 3 - .../desktop/AssetsList/AssetRow/AssetRow.tsx | 339 +++--------------- .../desktop/AssetsList/AssetRow/index.ts | 4 +- .../desktop/AssetsList/AssetsList.tsx | 26 +- .../src/components/desktop/CampaignWizard.tsx | 2 +- .../DesktopAccountSummary.tsx | 46 +++ .../desktop/DesktopAccountSummary/index.tsx | 1 + .../desktop/DesktopNavbar/AirdropZone.tsx | 8 +- .../desktop/DesktopNavbar/DesktopNavbar.tsx | 28 +- .../desktop/DesktopNavbar/WalletButton.tsx | 2 +- .../src/components/desktop/Earn/index.tsx | 2 +- .../desktop/UserPositions/UserPositions.tsx | 13 +- .../mobile/DesktopNavbar/AirdropZone.tsx | 6 +- .../mobile/DesktopNavbar/MobileNavbar.tsx | 4 +- .../mobile/DesktopNavbar/WalletButton.tsx | 2 +- .../MobileAccountSummary.tsx} | 18 +- .../mobile/MobileAccountSummary/index.ts | 1 + .../MobileAssetsList/AssetCard/AssetCard.tsx | 68 ++++ .../AssetCard/AssetCardStats.tsx | 48 +++ .../MobileAssetsList/AssetCard/index.ts | 1 + .../MobileAssetsList/MobileAssetsList.tsx | 64 ++++ .../mobile/MobileAssetsList/index.ts | 1 + .../src/hooks/useAssetItemData.ts | 40 +++ .../common => hooks}/useFirebaseAccount.tsx | 0 .../common => hooks}/useWalletContext.tsx | 0 apps/marginfi-v2-ui/src/pages/bridge.tsx | 2 +- apps/marginfi-v2-ui/src/pages/index.tsx | 77 ++-- apps/marginfi-v2-ui/src/pages/lip.tsx | 2 +- apps/marginfi-v2-ui/src/pages/points.tsx | 2 +- apps/marginfi-v2-ui/src/pages/swap.tsx | 2 +- apps/marginfi-v2-ui/src/utils/index.ts | 41 +-- apps/marginfi-v2-ui/src/utils/mrgnActions.ts | 196 ++++++++++ apps/marginfi-v2-ui/src/utils/mrgnUtils.ts | 38 ++ apps/marginfi-v2-ui/tailwind.config.js | 7 +- .../Lend/PoolCard/PoolCardStats.tsx | 4 +- 43 files changed, 866 insertions(+), 620 deletions(-) create mode 100644 apps/marginfi-v2-ui/src/components/common/AccountSummary/GlobalStats.tsx rename apps/marginfi-v2-ui/src/components/{desktop => common}/AccountSummary/UserStats.tsx (99%) create mode 100644 apps/marginfi-v2-ui/src/components/common/AccountSummary/index.ts rename apps/marginfi-v2-ui/src/components/{desktop => common}/AccountSummary/style.module.css (90%) rename apps/marginfi-v2-ui/src/components/{desktop/AssetsList => common/AssetList}/BorrowLendToggle.tsx (100%) create mode 100644 apps/marginfi-v2-ui/src/components/common/AssetList/index.ts create mode 100644 apps/marginfi-v2-ui/src/components/common/HtmlTooltip.tsx delete mode 100644 apps/marginfi-v2-ui/src/components/desktop/AccountSummary/GlobalStats.tsx delete mode 100644 apps/marginfi-v2-ui/src/components/desktop/AccountSummary/index.tsx create mode 100644 apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/DesktopAccountSummary.tsx create mode 100644 apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/index.tsx rename apps/marginfi-v2-ui/src/components/{desktop/AccountSummary/AccountSummary.tsx => mobile/MobileAccountSummary/MobileAccountSummary.tsx} (64%) create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/index.ts create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/index.ts create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/index.ts create mode 100644 apps/marginfi-v2-ui/src/hooks/useAssetItemData.ts rename apps/marginfi-v2-ui/src/{components/common => hooks}/useFirebaseAccount.tsx (100%) rename apps/marginfi-v2-ui/src/{components/common => hooks}/useWalletContext.tsx (100%) create mode 100644 apps/marginfi-v2-ui/src/utils/mrgnActions.ts create mode 100644 apps/marginfi-v2-ui/src/utils/mrgnUtils.ts diff --git a/apps/marginfi-v2-ui/src/components/common/AccountSummary/GlobalStats.tsx b/apps/marginfi-v2-ui/src/components/common/AccountSummary/GlobalStats.tsx new file mode 100644 index 0000000000..02d898fe9a --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/common/AccountSummary/GlobalStats.tsx @@ -0,0 +1,179 @@ +import { FC } from "react"; +import { Typography, Skeleton } from "@mui/material"; +import { numeralFormatter } from "@mrgnlabs/mrgn-common"; +import Image from "next/image"; +import Link from "next/link"; + +import { MrgnTooltip } from "~/components/desktop/Tooltip"; + +import styles from "./style.module.css"; + +interface GlobalStatsProps { + deposits: number; + borrows: number; + tvl: number; + pointsTotal: number | null; +} + +const GlobalStats: FC = ({ borrows, deposits, pointsTotal, tvl }) => { + return ( +
+
+
+ + Supplied +
+ + + Supplied + + Total value supplied across all assets in the marginfi protocol. + + } + placement="top" + > +
+ info +
+
+
+
+ + {deposits ? ( + `$${numeralFormatter(deposits)}` + ) : ( + + )} + +
+ +
+ + Borrowed +
+ + + Global Borrowed + + Total value borrowed across all assets in the marginfi protocol. + + } + placement="top" + > +
+ info +
+
+
+
+ + {borrows ? ( + `$${numeralFormatter(borrows)}` + ) : ( + + )} + +
+ +
+ + TVL +
+ + + Global TVL + +
+
Total value locked in the marginfi protocol, calculated as:
+
{"deposits - borrowed"}
+
+ + } + placement="top" + > +
+ info +
+
+
+
+ + {tvl ? ( + `$${numeralFormatter(tvl)}` + ) : ( + + )} + +
+ +
+ + Points +
+ + + Points + +
+
+ Learn more about points{" "} + + here + + . +
+
+ + } + placement="top" + > +
+ info +
+
+
+
+ + {pointsTotal ? ( + numeralFormatter(pointsTotal) + ) : ( + + )} + +
+
+
+ ); +}; + +const DividerLine = () =>
; + +export { GlobalStats }; diff --git a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/UserStats.tsx b/apps/marginfi-v2-ui/src/components/common/AccountSummary/UserStats.tsx similarity index 99% rename from apps/marginfi-v2-ui/src/components/desktop/AccountSummary/UserStats.tsx rename to apps/marginfi-v2-ui/src/components/common/AccountSummary/UserStats.tsx index 1fe1c66882..a735829781 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/UserStats.tsx +++ b/apps/marginfi-v2-ui/src/components/common/AccountSummary/UserStats.tsx @@ -1,11 +1,12 @@ +import React, { FC, useMemo } from "react"; +import { AccountSummary } from "@mrgnlabs/marginfi-v2-ui-state"; +import { usdFormatter, numeralFormatter, usdFormatterDyn, percentFormatter } from "@mrgnlabs/mrgn-common"; import { Typography, Skeleton } from "@mui/material"; import Image from "next/image"; import Link from "next/link"; -import { FC, useMemo } from "react"; + import { MrgnTooltip } from "~/components/desktop/Tooltip"; -import React from "react"; -import { AccountSummary } from "@mrgnlabs/marginfi-v2-ui-state"; -import { usdFormatter, numeralFormatter, usdFormatterDyn, percentFormatter } from "@mrgnlabs/mrgn-common"; + import styles from "./style.module.css"; interface UserStatsProps { diff --git a/apps/marginfi-v2-ui/src/components/common/AccountSummary/index.ts b/apps/marginfi-v2-ui/src/components/common/AccountSummary/index.ts new file mode 100644 index 0000000000..6e02c4c88e --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/common/AccountSummary/index.ts @@ -0,0 +1,2 @@ +export * from "./GlobalStats"; +export * from "./UserStats"; diff --git a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/style.module.css b/apps/marginfi-v2-ui/src/components/common/AccountSummary/style.module.css similarity index 90% rename from apps/marginfi-v2-ui/src/components/desktop/AccountSummary/style.module.css rename to apps/marginfi-v2-ui/src/components/common/AccountSummary/style.module.css index 4fa7c73639..ee1506516a 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/style.module.css +++ b/apps/marginfi-v2-ui/src/components/common/AccountSummary/style.module.css @@ -1,7 +1,7 @@ .hide-scrollbar { -ms-overflow-style: none; /* for Internet Explorer, Edge */ scrollbar-width: none; /* for Firefox */ - overflow-x: scroll; + overflow-x: scroll; } .hide-scrollbar::-webkit-scrollbar { diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/BorrowLendToggle.tsx b/apps/marginfi-v2-ui/src/components/common/AssetList/BorrowLendToggle.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/desktop/AssetsList/BorrowLendToggle.tsx rename to apps/marginfi-v2-ui/src/components/common/AssetList/BorrowLendToggle.tsx diff --git a/apps/marginfi-v2-ui/src/components/common/AssetList/index.ts b/apps/marginfi-v2-ui/src/components/common/AssetList/index.ts new file mode 100644 index 0000000000..8442d9cd65 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/common/AssetList/index.ts @@ -0,0 +1 @@ +export * from "./BorrowLendToggle"; diff --git a/apps/marginfi-v2-ui/src/components/common/HtmlTooltip.tsx b/apps/marginfi-v2-ui/src/components/common/HtmlTooltip.tsx new file mode 100644 index 0000000000..15c924d0bc --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/common/HtmlTooltip.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { styled } from "@mui/material/styles"; +import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; + +export const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( + +))(({ theme }) => ({ + [`& .${tooltipClasses.tooltip}`]: { + backgroundColor: "rgb(227, 227, 227)", + color: "rgba(0, 0, 0, 0.87)", + maxWidth: 220, + fontSize: theme.typography.pxToRem(12), + border: "1px solid #dadde9", + }, +})); diff --git a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/GlobalStats.tsx b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/GlobalStats.tsx deleted file mode 100644 index e34da6210c..0000000000 --- a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/GlobalStats.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { Typography, Skeleton } from "@mui/material"; -import Image from "next/image"; -import Link from "next/link"; -import { FC } from "react"; -import { MrgnTooltip } from "~/components/desktop/Tooltip"; -import styles from "./style.module.css"; -import { numeralFormatter } from "@mrgnlabs/mrgn-common"; - -interface GlobalStatsProps { - deposits: number; - borrows: number; - tvl: number; - pointsTotal: number | null; -} - -const GlobalStats: FC = ({ borrows, deposits, pointsTotal, tvl }) => { - return ( -
- Global stats -
-
-
-
- - Supplied -
- - - Supplied - - Total value supplied across all assets in the marginfi protocol. - - } - placement="top" - > - info - -
-
- - {deposits ? ( - `$${numeralFormatter(deposits)}` - ) : ( - - )} - -
-
- -
-
- - Borrowed -
- - - Global Borrowed - - Total value borrowed across all assets in the marginfi protocol. - - } - placement="top" - > - info - -
-
- - {borrows ? ( - `$${numeralFormatter(borrows)}` - ) : ( - - )} - -
-
- -
-
- - TVL -
- - - Global TVL - -
-
Total value locked in the marginfi protocol, calculated as:
-
{"deposits - borrowed"}
-
- - } - placement="top" - > - info -
-
-
- - {tvl ? ( - `$${numeralFormatter(tvl)}` - ) : ( - - )} - -
-
- -
-
- - Points -
- - - Points - -
-
- Learn more about points{" "} - - here - - . -
-
- - } - placement="top" - > - info -
-
-
- - {pointsTotal ? ( - numeralFormatter(pointsTotal) - ) : ( - - )} - -
-
-
-
-
- ); -}; - -const DividerLine = () =>
; - -export { GlobalStats }; diff --git a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/index.tsx deleted file mode 100644 index 5a0d9fcc26..0000000000 --- a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { AccountSummary } from "./AccountSummary"; - -export { AccountSummary }; diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx index 828a4da588..33dcd16122 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx @@ -1,15 +1,12 @@ +import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; import Image from "next/image"; import { TableCell, TableRow } from "@mui/material"; -import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; -import { toast } from "react-toastify"; -import { AssetRowInputBox } from "./AssetRowInputBox"; -import { AssetRowAction } from "./AssetRowAction"; import { styled } from "@mui/material/styles"; import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; import { useMrgnlendStore, useUserProfileStore } from "~/store"; import Badge from "@mui/material/Badge"; -import { isWholePosition } from "~/utils"; + import { WSOL_MINT, groupedNumberFormatterDyn, @@ -18,31 +15,16 @@ import { uiToNative, usdFormatter, } from "@mrgnlabs/mrgn-common"; -import { - ExtendedBankInfo, - Emissions, - FEE_MARGIN, - ActionType, - getCurrentAction, - ExtendedBankMetadata, -} from "@mrgnlabs/marginfi-v2-ui-state"; +import { ExtendedBankInfo, ActionType, getCurrentAction, ExtendedBankMetadata } from "@mrgnlabs/marginfi-v2-ui-state"; import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2"; -import { useWalletContext } from "~/components/common/useWalletContext"; -const CLOSE_BALANCE_TOAST_ID = "close-balance"; -const BORROW_OR_LEND_TOAST_ID = "borrow-or-lend"; +import { borrowOrLend, closeBalance } from "~/utils"; +import { useWalletContext } from "~/hooks/useWalletContext"; +import { useAssetItemData } from "~/hooks/useAssetItemData"; +import { HtmlTooltip } from "~/components/common/HtmlTooltip"; -const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( - -))(({ theme }) => ({ - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: "rgb(227, 227, 227)", - color: "rgba(0, 0, 0, 0.87)", - maxWidth: 220, - fontSize: theme.typography.pxToRem(12), - border: "1px solid #dadde9", - }, -})); +import { AssetRowInputBox } from "./AssetRowInputBox"; +import { AssetRowAction } from "./AssetRowAction"; const AssetRow: FC<{ bank: ExtendedBankInfo; @@ -68,6 +50,16 @@ const AssetRow: FC<{ const [lendZoomLevel, denominationUSD] = useUserProfileStore((state) => [state.lendZoomLevel, state.denominationUSD]); const setIsRefreshingStore = useMrgnlendStore((state) => state.setIsRefreshingStore); const [mfiClient, fetchMrgnlendState] = useMrgnlendStore((state) => [state.marginfiClient, state.fetchMrgnlendState]); + const { rateAP, assetWeight, isBankFilled, isBankHigh, bankFilled } = useAssetItemData({ bank, isInLendingMode }); + + const assetPriceOffset = useMemo( + () => + Math.max( + bank.info.rawBank.getPrice(bank.info.oraclePrice, PriceBias.Highest).toNumber() - bank.info.state.price, + bank.info.state.price - bank.info.rawBank.getPrice(bank.info.oraclePrice, PriceBias.Lowest).toNumber() + ), + [bank.info] + ); const [borrowOrLendAmount, setBorrowOrLendAmount] = useState(0); @@ -99,42 +91,11 @@ const AssetRow: FC<{ setBorrowOrLendAmount(0); }, [isInLendingMode]); - const closeBalance = useCallback(async () => { - if (!marginfiAccount) { - toast.error("marginfi account not ready."); - return; - } - - if (!bank.isActive) { - toast.error("no position to close."); - return; - } - - toast.loading("Closing dust balance", { - toastId: CLOSE_BALANCE_TOAST_ID, - }); - + const handleCloseBalance = useCallback(async () => { try { - if (bank.position.isLending) { - await marginfiAccount.withdraw(0, bank.address, true); - } else { - await marginfiAccount.repay(0, bank.address, true); - } - toast.update(CLOSE_BALANCE_TOAST_ID, { - render: "Closing 👍", - type: toast.TYPE.SUCCESS, - autoClose: 2000, - isLoading: false, - }); - } catch (error: any) { - toast.update(CLOSE_BALANCE_TOAST_ID, { - render: `Error while closing balance: ${error.message}`, - type: toast.TYPE.ERROR, - autoClose: 5000, - isLoading: false, - }); - console.log(`Error while closing balance`); - console.log(error); + closeBalance({ marginfiAccount, bank }); + } catch (error) { + return; } setBorrowOrLendAmount(0); @@ -148,130 +109,8 @@ const AssetRow: FC<{ } }, [bank, marginfiAccount, fetchMrgnlendState, setIsRefreshingStore]); - const borrowOrLend = useCallback(async () => { - if (mfiClient === null) throw Error("Marginfi client not ready"); - - if ( - currentAction === ActionType.Deposit && - bank.info.state.totalDeposits >= bank.info.rawBank.config.depositLimit - ) { - toast.error( - `${bank.meta.tokenSymbol} deposit limit has been been reached. Additional deposits are not currently available.` - ); - return; - } - - if (currentAction === ActionType.Borrow && bank.info.state.totalBorrows >= bank.info.rawBank.config.borrowLimit) { - toast.error( - `${bank.meta.tokenSymbol} borrow limit has been been reached. Additional borrows are not currently available.` - ); - return; - } - - if (currentAction === ActionType.Deposit && bank.userInfo.maxDeposit === 0) { - toast.error(`You don't have any ${bank.meta.tokenSymbol} to lend in your wallet.`); - return; - } - - if (currentAction === ActionType.Borrow && bank.userInfo.maxBorrow === 0) { - toast.error(`You cannot borrow any ${bank.meta.tokenSymbol} right now.`); - return; - } - - if (borrowOrLendAmount <= 0) { - toast.error("Please enter an amount over 0."); - return; - } - - let _marginfiAccount = marginfiAccount; - - if (nativeSolBalance < FEE_MARGIN) { - toast.error("Not enough sol for fee."); - return; - } - - // -------- Create marginfi account if needed - try { - if (!_marginfiAccount) { - if (currentAction !== ActionType.Deposit) { - toast.error("An account is required for anything operation except deposit."); - return; - } - - toast.loading("Creating account", { - toastId: BORROW_OR_LEND_TOAST_ID, - }); - - _marginfiAccount = await mfiClient.createMarginfiAccount(); - toast.update(BORROW_OR_LEND_TOAST_ID, { - render: `${currentAction + "ing"} ${borrowOrLendAmount} ${bank.meta.tokenSymbol}`, - }); - } - } catch (error: any) { - toast.update(BORROW_OR_LEND_TOAST_ID, { - render: `Error while ${currentAction + "ing"}: ${error.message}`, - type: toast.TYPE.ERROR, - autoClose: 5000, - isLoading: false, - }); - console.log(`Error while ${currentAction + "ing"}`); - console.log(error); - return; - } - - // -------- Perform relevant operation - try { - if (currentAction === ActionType.Deposit) { - await _marginfiAccount.deposit(borrowOrLendAmount, bank.address); - - toast.update(BORROW_OR_LEND_TOAST_ID, { - render: `${currentAction + "ing"} ${borrowOrLendAmount} ${bank.meta.tokenSymbol} 👍`, - type: toast.TYPE.SUCCESS, - autoClose: 2000, - isLoading: false, - }); - } - - toast.loading(`${currentAction + "ing"} ${borrowOrLendAmount} ${bank.meta.tokenSymbol}`, { - toastId: BORROW_OR_LEND_TOAST_ID, - }); - if (_marginfiAccount === null) { - // noinspection ExceptionCaughtLocallyJS - throw Error("Marginfi account not ready"); - } - - if (currentAction === ActionType.Borrow) { - await _marginfiAccount.borrow(borrowOrLendAmount, bank.address); - } else if (currentAction === ActionType.Repay) { - await _marginfiAccount.repay( - borrowOrLendAmount, - bank.address, - bank.isActive && isWholePosition(bank, borrowOrLendAmount) - ); - } else if (currentAction === ActionType.Withdraw) { - await _marginfiAccount.withdraw( - borrowOrLendAmount, - bank.address, - bank.isActive && isWholePosition(bank, borrowOrLendAmount) - ); - } - - toast.update(BORROW_OR_LEND_TOAST_ID, { - render: `${currentAction + "ing"} ${borrowOrLendAmount} ${bank.meta.tokenSymbol} 👍`, - type: toast.TYPE.SUCCESS, - autoClose: 2000, - isLoading: false, - }); - } catch (error: any) { - toast.update(BORROW_OR_LEND_TOAST_ID, { - render: `Error while ${currentAction + "ing"}: ${error.message}`, - type: toast.TYPE.ERROR, - autoClose: 5000, - isLoading: false, - }); - console.log(`Error while ${currentAction + "ing"}`); - console.log(error); - } + const handleBorrowOrLend = useCallback(async () => { + borrowOrLend({ mfiClient, currentAction, bank, borrowOrLendAmount, nativeSolBalance, marginfiAccount }); setBorrowOrLendAmount(0); @@ -309,6 +148,7 @@ const AssetRow: FC<{
{bank.meta.tokenSymbol}
+
@@ -441,11 +241,7 @@ const AssetRow: FC<{ align="right" style={{ fontWeight: 300 }} > - {isInLendingMode - ? bank.info.rawBank.config.assetWeightInit.toNumber() > 0 - ? (bank.info.rawBank.config.assetWeightInit.toNumber() * 100).toFixed(0) + "%" - : "-" - : ((1 / bank.info.rawBank.config.liabilityWeightInit.toNumber()) * 100).toFixed(0) + "%"} + {assetWeight} - {isInLendingMode - ? bank.info.state.totalDeposits >= bank.info.rawBank.config.depositLimit * 0.99999 - ? "Limit Reached" - : bank.info.state.totalDeposits >= bank.info.rawBank.config.depositLimit * 0.9 - ? "Approaching Limit" - : null - : bank.info.state.totalBorrows >= bank.info.rawBank.config.borrowLimit * 0.99999 - ? "Limit Reached" - : bank.info.state.totalBorrows >= bank.info.rawBank.config.borrowLimit * 0.9 - ? "Approaching Limit" - : null} + {isBankHigh && (isBankFilled ? "Limit Reached" : "Approaching Limit")} {`${bank.meta.tokenSymbol} ${isInLendingMode ? "deposits" : "borrows"} are at ${percentFormatter.format( - isInLendingMode - ? bank.info.state.totalDeposits / bank.info.rawBank.config.depositLimit - : bank.info.state.totalBorrows / bank.info.rawBank.config.borrowLimit + (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) / bankFilled )} capacity.`}
@@ -481,45 +265,17 @@ const AssetRow: FC<{ } placement="right" - className={`${ - isInLendingMode - ? bank.info.state.totalDeposits >= bank.info.rawBank.config.depositLimit * 0.9 - ? "" - : "" - : bank.info.state.totalBorrows >= bank.info.rawBank.config.borrowLimit * 0.9 - ? "" - : "" - }`} + className={``} > = bank.info.rawBank.config.depositLimit * 0.99999 - ? "💯" - : bank.info.state.totalDeposits >= bank.info.rawBank.config.depositLimit * 0.9 - ? "❗" - : null - : bank.info.state.totalBorrows >= bank.info.rawBank.config.borrowLimit * 0.99999 - ? "💯" - : bank.info.state.totalBorrows >= bank.info.rawBank.config.borrowLimit * 0.9 - ? "❗" - : null - } + badgeContent={isBankHigh && (isBankFilled ? "💯" : "❗")} className="bg-transparent" sx={{ "& .MuiBadge-badge": { fontSize: 20, }, }} - invisible={ - isInLendingMode - ? bank.info.state.totalDeposits >= bank.info.rawBank.config.depositLimit * 0.9 - ? false - : true - : bank.info.state.totalBorrows >= bank.info.rawBank.config.borrowLimit * 0.9 - ? false - : true - } + invisible={!isBankHigh} > {denominationUSD ? usdFormatter.format( @@ -562,17 +318,10 @@ const AssetRow: FC<{ style={{ fontWeight: 300 }} > {denominationUSD - ? usdFormatter.format( - (isInLendingMode ? bank.info.rawBank.config.depositLimit : bank.info.rawBank.config.borrowLimit) * - bank.info.state.price - ) + ? usdFormatter.format(bankFilled * bank.info.state.price) : lendZoomLevel < 2 - ? groupedNumberFormatterDyn.format( - isInLendingMode ? bank.info.rawBank.config.depositLimit : bank.info.rawBank.config.borrowLimit - ) - : numeralFormatter( - isInLendingMode ? bank.info.rawBank.config.depositLimit : bank.info.rawBank.config.borrowLimit - )} + ? groupedNumberFormatterDyn.format(bankFilled) + : numeralFormatter(bankFilled)}
)} @@ -631,7 +380,7 @@ const AssetRow: FC<{ maxDecimals={bank.info.state.mintDecimals} inputRefs={inputRefs} disabled={isDust || currentAction === "Connect" || maxAmount === 0} - onEnter={borrowOrLend} + onEnter={handleBorrowOrLend} /> @@ -650,7 +399,9 @@ const AssetRow: FC<{ ? "rgb(227, 227, 227)" : "rgba(0,0,0,0)" } - onClick={currentAction === "Connect" ? openWalletSelector : isDust ? closeBalance : borrowOrLend} + onClick={ + currentAction === "Connect" ? openWalletSelector : isDust ? handleCloseBalance : handleBorrowOrLend + } disabled={ currentAction !== "Connect" && ((isDust && uiToNative(bank.userInfo.tokenAccount.balance, bank.info.state.mintDecimals).isZero()) || diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/index.ts b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/index.ts index 15b51ef0e4..0b6ef37c12 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/index.ts +++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/index.ts @@ -1,3 +1 @@ -import { AssetRow } from "./AssetRow"; - -export default AssetRow; +export * from "./AssetRow"; diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx index 244fdc86cd..b03c4d3443 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx @@ -1,27 +1,17 @@ -import Image from "next/image"; import React, { FC, useEffect, useRef, useState } from "react"; +import Image from "next/image"; +import { useHotkeys } from "react-hotkeys-hook"; import { Card, Table, TableHead, TableBody, TableContainer, TableCell } from "@mui/material"; import { styled } from "@mui/material/styles"; import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; -import { BorrowLendToggle } from "./BorrowLendToggle"; -import AssetRow from "./AssetRow"; + import { useMrgnlendStore, useUserProfileStore } from "~/store"; -import { useHotkeys } from "react-hotkeys-hook"; -import { LoadingAsset } from "./AssetRow/AssetRow"; -import { useWalletContext } from "../../common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; +import { BorrowLendToggle } from "~/components/common/AssetList/BorrowLendToggle"; -const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( - -))(({ theme }) => ({ - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: "rgb(227, 227, 227)", - color: "rgba(0, 0, 0, 0.87)", - maxWidth: 220, - fontSize: theme.typography.pxToRem(12), - border: "1px solid #dadde9", - }, -})); +import { LoadingAsset, AssetRow } from "./AssetRow"; +import { HtmlTooltip } from "~/components/common/HtmlTooltip"; const AssetsList: FC = () => { // const { selectedAccount, nativeSolBalance } = useStore(); @@ -97,7 +87,7 @@ const AssetsList: FC = () => { ); // Hack required to circumvent rehydration error - const [hasMounted, setHasMounted] = React.useState(false); + const [hasMounted, setHasMounted] = useState(false); useEffect(() => { setHasMounted(true); }, []); diff --git a/apps/marginfi-v2-ui/src/components/desktop/CampaignWizard.tsx b/apps/marginfi-v2-ui/src/components/desktop/CampaignWizard.tsx index 6c2747e447..a3a2aed5f7 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/CampaignWizard.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/CampaignWizard.tsx @@ -20,7 +20,7 @@ import { NumberFormatValues, NumericFormat } from "react-number-format"; import { useMrgnlendStore } from "~/store"; import { computeGuaranteedApy } from "@mrgnlabs/lip-client"; import { EarnAction } from "./Earn"; -import { useWalletContext } from "~/components/common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; interface CampaignWizardInputBox { value: number; diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/DesktopAccountSummary.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/DesktopAccountSummary.tsx new file mode 100644 index 0000000000..3e99c6f6fa --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/DesktopAccountSummary.tsx @@ -0,0 +1,46 @@ +import React, { FC } from "react"; +import { useMrgnlendStore } from "~/store"; +import dynamic from "next/dynamic"; +import { useWalletContext } from "~/hooks/useWalletContext"; +import { UserStats } from "~/components/common/AccountSummary"; + +const GlobalStats = dynamic(async () => (await import("~/components/common/AccountSummary/GlobalStats")).GlobalStats, { + ssr: false, +}); + +const AccountSummary: FC = () => { + const [isStoreInitialized, accountSummary, protocolStats, selectedAccount] = useMrgnlendStore((state) => [ + state.initialized, + state.accountSummary, + state.protocolStats, + state.selectedAccount, + ]); + const { connected } = useWalletContext(); + + return ( +
+
+
+ Global stats + +
+
+ +
+ {connected && ( + + )} +
+
+ ); +}; + +export { AccountSummary as DesktopAccountSummary }; diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/index.tsx new file mode 100644 index 0000000000..2dcb49a741 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/index.tsx @@ -0,0 +1 @@ +export * from "./DesktopAccountSummary"; diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.tsx index a496b30197..4d416cc30b 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/AirdropZone.tsx @@ -2,7 +2,7 @@ import { Button, Modal } from "@mui/material"; import { FC, useCallback, useState } from "react"; import styles from "./AirdropZone.module.css"; import { PublicKey, Transaction } from "@solana/web3.js"; -import { useConnection, useWallet } from "@solana/wallet-adapter-react"; +import { useConnection } from "@solana/wallet-adapter-react"; import { makeAirdropCollateralIx } from "~/utils"; import { toast } from "react-toastify"; import { @@ -10,7 +10,7 @@ import { getAssociatedTokenAddressSync, shortenAddress, } from "@mrgnlabs/mrgn-common"; -import { useWalletContext } from "../../common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; const SOL_AMOUNT = 2 * 10 ** 9; @@ -60,9 +60,7 @@ const AirdropZone: FC = () => { return (
- - Airdrop - + Airdrop
diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx index a24713530a..c5da39f773 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx @@ -10,9 +10,9 @@ import { useMrgnlendStore, useUserProfileStore } from "~/store"; import { useRouter } from "next/router"; import { HotkeysEvent } from "react-hotkeys-hook/dist/types"; import { Badge } from "@mui/material"; -import { useFirebaseAccount } from "../../common/useFirebaseAccount"; +import { useFirebaseAccount } from "~/hooks/useFirebaseAccount"; import { groupedNumberFormatterDyn, numeralFormatter } from "@mrgnlabs/mrgn-common"; -import { useWalletContext } from "../../common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; // @todo implement second pretty navbar row const DesktopNavbar: FC = () => { @@ -133,7 +133,12 @@ const DesktopNavbar: FC = () => { badgeContent={"l"} invisible={!showBadges} > - + lend @@ -152,7 +157,10 @@ const DesktopNavbar: FC = () => { badgeContent={"s"} invisible={!showBadges} > - + swap @@ -170,7 +178,10 @@ const DesktopNavbar: FC = () => { badgeContent={"b"} invisible={!showBadges} > - + bridge @@ -190,7 +201,12 @@ const DesktopNavbar: FC = () => { invisible={!showBadges} className="hidden md:block" > - + earn diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx index 5e0cd4ee7e..e0811cd095 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx @@ -1,6 +1,6 @@ import dynamic from "next/dynamic"; import { FC } from "react"; -import { useWalletContext } from "../../common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; const WalletMultiButtonDynamic = dynamic( async () => (await import("@solana/wallet-adapter-react-ui")).WalletMultiButton, diff --git a/apps/marginfi-v2-ui/src/components/desktop/Earn/index.tsx b/apps/marginfi-v2-ui/src/components/desktop/Earn/index.tsx index 2b0760c16c..866fa32e69 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/Earn/index.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/Earn/index.tsx @@ -31,7 +31,7 @@ import { Bank, PriceBias } from "@mrgnlabs/marginfi-client-v2"; import { Countdown } from "~/components/desktop/Countdown"; import { toast } from "react-toastify"; import BigNumber from "bignumber.js"; -import { useWalletContext } from "~/components/common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; import { useMrgnlendStore } from "~/store"; const Earn = () => { diff --git a/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx index 9a7e189556..47d735e7b1 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx @@ -7,18 +7,7 @@ import Image from "next/image"; import Link from "next/link"; import { useMrgnlendStore } from "~/store"; import { ActiveBankInfo } from "@mrgnlabs/marginfi-v2-ui-state"; - -const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( - -))(({ theme }) => ({ - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: "rgb(227, 227, 227)", - color: "rgba(0, 0, 0, 0.87)", - maxWidth: 220, - fontSize: theme.typography.pxToRem(12), - border: "1px solid #dadde9", - }, -})); +import { HtmlTooltip } from "~/components/common/HtmlTooltip"; const UserPositions: FC = () => { const setIsRefreshingStore = useMrgnlendStore((state) => state.setIsRefreshingStore); diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx index a496b30197..ebc76465b2 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx @@ -10,7 +10,7 @@ import { getAssociatedTokenAddressSync, shortenAddress, } from "@mrgnlabs/mrgn-common"; -import { useWalletContext } from "../../common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; const SOL_AMOUNT = 2 * 10 ** 9; @@ -60,9 +60,7 @@ const AirdropZone: FC = () => { return (
- - Airdrop - + Airdrop
diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx index 5269b30ee6..947e008c87 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx @@ -4,8 +4,8 @@ import Image from "next/image"; import AirdropZone from "./AirdropZone"; import { useUserProfileStore } from "~/store"; import { useRouter } from "next/router"; -import { useFirebaseAccount } from "../../common/useFirebaseAccount"; -import { useWalletContext } from "../../common/useWalletContext"; +import { useFirebaseAccount } from "~/hooks/useFirebaseAccount"; +import { useWalletContext } from "~/hooks/useWalletContext"; // @todo implement second pretty navbar row const MobileNavbar: FC = () => { diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx index 4959bdf3d1..e0811cd095 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx @@ -1,6 +1,6 @@ import dynamic from "next/dynamic"; import { FC } from "react"; -import { useWalletContext } from "~/components/common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; const WalletMultiButtonDynamic = dynamic( async () => (await import("@solana/wallet-adapter-react-ui")).WalletMultiButton, diff --git a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/AccountSummary.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/MobileAccountSummary.tsx similarity index 64% rename from apps/marginfi-v2-ui/src/components/desktop/AccountSummary/AccountSummary.tsx rename to apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/MobileAccountSummary.tsx index e8f06d0c79..91183d5353 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AccountSummary/AccountSummary.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/MobileAccountSummary.tsx @@ -1,10 +1,12 @@ import React, { FC } from "react"; -import { UserStats } from "./UserStats"; import { useMrgnlendStore } from "~/store"; import dynamic from "next/dynamic"; -import { useWalletContext } from "../../common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; +import { UserStats } from "~/components/common/AccountSummary"; -const GlobalStats = dynamic(async () => (await import("./GlobalStats")).GlobalStats, { ssr: false }); +const GlobalStats = dynamic(async () => (await import("~/components/common/AccountSummary/GlobalStats")).GlobalStats, { + ssr: false, +}); const AccountSummary: FC = () => { const [isStoreInitialized, accountSummary, protocolStats, selectedAccount] = useMrgnlendStore((state) => [ @@ -16,8 +18,8 @@ const AccountSummary: FC = () => { const { connected } = useWalletContext(); return ( -
-
+
+
{ />
-
+ {/*
{connected && ( )} -
+
*/}
); }; -export { AccountSummary }; +export { AccountSummary as MobileAccountSummary }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/index.ts b/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/index.ts new file mode 100644 index 0000000000..0bdb04e467 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/index.ts @@ -0,0 +1 @@ +export * from "./MobileAccountSummary"; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx new file mode 100644 index 0000000000..5298fc1bd6 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx @@ -0,0 +1,68 @@ +import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; +import Image from "next/image"; +import { TableCell, TableRow } from "@mui/material"; +import { styled } from "@mui/material/styles"; +import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; +import Typography from "@mui/material/Typography"; +import { useMrgnlendStore, useUserProfileStore } from "~/store"; +import Badge from "@mui/material/Badge"; + +import { + WSOL_MINT, + groupedNumberFormatterDyn, + numeralFormatter, + percentFormatter, + uiToNative, + usdFormatter, +} from "@mrgnlabs/mrgn-common"; +import { ExtendedBankInfo, ActionType, getCurrentAction, ExtendedBankMetadata } from "@mrgnlabs/marginfi-v2-ui-state"; +import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2"; + +import { borrowOrLend, closeBalance } from "~/utils"; +import { useWalletContext } from "~/hooks/useWalletContext"; +import { useAssetItemData } from "~/hooks/useAssetItemData"; +import { HtmlTooltip } from "~/components/common/HtmlTooltip"; + +export const AssetCard: FC<{ + bank: ExtendedBankInfo; + nativeSolBalance: number; + isInLendingMode: boolean; + isConnected: boolean; + marginfiAccount: MarginfiAccountWrapper | null; + inputRefs: React.MutableRefObject>; + hasHotkey: boolean; + showHotkeyBadges?: boolean; + badgeContent?: string; +}> = ({ + bank, + nativeSolBalance, + isInLendingMode, + marginfiAccount, + inputRefs, + hasHotkey, + showHotkeyBadges, + badgeContent, +}) => { + const { rateAP, assetWeight, isBankFilled, isBankHigh, bankFilled } = useAssetItemData({ bank, isInLendingMode }); + + return ( +
+
+
+
+ {bank.meta.tokenLogoUri && ( + {bank.meta.tokenSymbol} + )} +
+
+
{bank.meta.tokenSymbol}
+
{usdFormatter.format(bank.info.state.price)}
+
+
+
+
{rateAP.concat(...[" ", isInLendingMode ? "APY" : "APR"])}
+
+
+
+ ); +}; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx new file mode 100644 index 0000000000..62a941a620 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx @@ -0,0 +1,48 @@ +import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; +import Image from "next/image"; +import { TableCell, TableRow } from "@mui/material"; +import { styled } from "@mui/material/styles"; +import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; +import Typography from "@mui/material/Typography"; +import { useMrgnlendStore, useUserProfileStore } from "~/store"; +import Badge from "@mui/material/Badge"; + +import { + WSOL_MINT, + groupedNumberFormatterDyn, + numeralFormatter, + percentFormatter, + uiToNative, + usdFormatter, +} from "@mrgnlabs/mrgn-common"; +import { ExtendedBankInfo, ActionType, getCurrentAction, ExtendedBankMetadata } from "@mrgnlabs/marginfi-v2-ui-state"; +import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2"; + +export const AssetStats: FC<{ + bank: ExtendedBankInfo; + assetWeight: string; + isInLendingMode: boolean; + userBalance: string; +}> = ({ bank, assetWeight, isInLendingMode, userBalance }) => { + return ( +
+
+
Weight
+
{assetWeight}
+
+ {/* TODO: Add seperator */} +
+
{isInLendingMode ? "Deposits" : "Available"}
+
{0}
+ {/* {isHigh && ( +
{percentFormatter.format(bankFilled)}
+ )} */} +
+ {/* TODO: Add seperator */} +
+
Your Balance
+
{userBalance + " " + bank.meta.tokenSymbol}
+
+
+ ); +}; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/index.ts b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/index.ts new file mode 100644 index 0000000000..bc24b443ef --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/index.ts @@ -0,0 +1 @@ +export * from "./AssetCard"; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx new file mode 100644 index 0000000000..3528673ecf --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx @@ -0,0 +1,64 @@ +import React, { FC, useEffect, useRef, useState } from "react"; +import Image from "next/image"; +import { useHotkeys } from "react-hotkeys-hook"; +import { Card, Table, TableHead, TableBody, TableContainer, TableCell } from "@mui/material"; +import { styled } from "@mui/material/styles"; +import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; +import Typography from "@mui/material/Typography"; + +import { useMrgnlendStore, useUserProfileStore } from "~/store"; +import { useWalletContext } from "~/hooks/useWalletContext"; +import { BorrowLendToggle } from "~/components/common/AssetList/BorrowLendToggle"; +import { AssetCard } from "./AssetCard"; + +// import { LoadingAsset, AssetRow } from "./AssetRow"; + +export const MobileAssetsList: FC = () => { + const { connected } = useWalletContext(); + const [isStoreInitialized, sortedBanks, nativeSolBalance, selectedAccount] = useMrgnlendStore((state) => [ + state.initialized, + state.extendedBankInfos, + state.nativeSolBalance, + state.selectedAccount, + ]); + const [lendZoomLevel, showBadges, setShowBadges] = useUserProfileStore((state) => [ + state.lendZoomLevel, + state.showBadges, + state.setShowBadges, + ]); + const inputRefs = useRef>({}); + const [isInLendingMode, setIsInLendingMode] = useState(true); + const [isHotkeyMode, setIsHotkeyMode] = useState(false); + + return ( + <> +
+ +
+
+
Global pool
+ {sortedBanks + .filter((b) => !b.info.state.isIsolated) + .map((bank, i) => + isStoreInitialized ? ( + + ) : ( + // TODO add skeleton lib & component if green light + <> + ) + )} +
+ + ); +}; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/index.ts b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/index.ts new file mode 100644 index 0000000000..4f65b5a204 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/index.ts @@ -0,0 +1 @@ +export * from "./MobileAssetsList"; diff --git a/apps/marginfi-v2-ui/src/hooks/useAssetItemData.ts b/apps/marginfi-v2-ui/src/hooks/useAssetItemData.ts new file mode 100644 index 0000000000..3c469c3d5b --- /dev/null +++ b/apps/marginfi-v2-ui/src/hooks/useAssetItemData.ts @@ -0,0 +1,40 @@ +import { ExtendedBankInfo, Emissions } from "@mrgnlabs/marginfi-v2-ui-state"; +import { PriceBias } from "@mrgnlabs/marginfi-client-v2"; +import { useMemo } from "react"; +import { percentFormatter } from "@mrgnlabs/mrgn-common"; + +export function useAssetItemData({ bank, isInLendingMode }: { bank: ExtendedBankInfo; isInLendingMode: boolean }) { + const rateAP = useMemo( + () => + percentFormatter.format( + (isInLendingMode ? bank.info.state.lendingRate : bank.info.state.borrowingRate) + + (isInLendingMode && bank.info.state.emissions == Emissions.Lending ? bank.info.state.emissionsRate : 0) + + (!isInLendingMode && bank.info.state.emissions == Emissions.Borrowing ? bank.info.state.emissionsRate : 0) + ), + [isInLendingMode, bank.info.state] + ); + + const assetWeight = useMemo(() => { + if (bank.info.rawBank.config.assetWeightInit.toNumber() <= 0) { + return "-"; + } + return isInLendingMode + ? (bank.info.rawBank.config.assetWeightInit.toNumber() * 100).toFixed(0) + "%" + : ((1 / bank.info.rawBank.config.liabilityWeightInit.toNumber()) * 100).toFixed(0) + "%"; + }, [isInLendingMode, bank.info.rawBank.config]); + + const bankFilled = useMemo( + () => (isInLendingMode ? bank.info.rawBank.config.depositLimit : bank.info.rawBank.config.borrowLimit), + [isInLendingMode, bank.info.rawBank.config] + ); + const isBankFilled = useMemo( + () => (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) >= bankFilled * 0.99999, + [bankFilled, isInLendingMode, bank.info.state] + ); + const isBankHigh = useMemo( + () => (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) >= bankFilled * 0.9, + [bankFilled, isInLendingMode, bank.info.state] + ); + + return { rateAP, assetWeight, bankFilled, isBankFilled, isBankHigh }; +} diff --git a/apps/marginfi-v2-ui/src/components/common/useFirebaseAccount.tsx b/apps/marginfi-v2-ui/src/hooks/useFirebaseAccount.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/common/useFirebaseAccount.tsx rename to apps/marginfi-v2-ui/src/hooks/useFirebaseAccount.tsx diff --git a/apps/marginfi-v2-ui/src/components/common/useWalletContext.tsx b/apps/marginfi-v2-ui/src/hooks/useWalletContext.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/common/useWalletContext.tsx rename to apps/marginfi-v2-ui/src/hooks/useWalletContext.tsx diff --git a/apps/marginfi-v2-ui/src/pages/bridge.tsx b/apps/marginfi-v2-ui/src/pages/bridge.tsx index ef0b695dd7..96bbb1e082 100644 --- a/apps/marginfi-v2-ui/src/pages/bridge.tsx +++ b/apps/marginfi-v2-ui/src/pages/bridge.tsx @@ -8,7 +8,7 @@ import { useHotkeys } from "react-hotkeys-hook"; import { PageHeaderBridge } from "~/components/desktop/PageHeader"; import { MayanWidgetColors, MayanWidgetConfigType } from "~/types"; import { useUserProfileStore } from "~/store"; -import { useWalletContext } from "~/components/common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; const tokens = [ "0x0000000000000000000000000000000000000000", // SOL diff --git a/apps/marginfi-v2-ui/src/pages/index.tsx b/apps/marginfi-v2-ui/src/pages/index.tsx index a437b76e88..759d99aea8 100644 --- a/apps/marginfi-v2-ui/src/pages/index.tsx +++ b/apps/marginfi-v2-ui/src/pages/index.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from "react"; import { Banner } from "~/components/desktop/Banner"; import { PageHeader } from "~/components/desktop/PageHeader"; -import { useWalletContext } from "~/components/common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; import { shortenAddress } from "@mrgnlabs/mrgn-common"; import config from "~/config/marginfi"; import { useMrgnlendStore } from "../store"; @@ -10,11 +10,26 @@ import { OverlaySpinner } from "~/components/desktop/OverlaySpinner"; import { useConnection } from "@solana/wallet-adapter-react"; import { Desktop, Mobile } from "~/mediaQueries"; -const AccountSummary = dynamic(async () => (await import("~/components/desktop/AccountSummary")).AccountSummary, { +const DesktopAccountSummary = dynamic( + async () => (await import("~/components/desktop/DesktopAccountSummary")).DesktopAccountSummary, + { + ssr: false, + } +); +const MobileAccountSummary = dynamic( + async () => (await import("~/components/mobile/MobileAccountSummary")).MobileAccountSummary, + { + ssr: false, + } +); +const AssetsList = dynamic(async () => (await import("~/components/desktop/AssetsList")).AssetsList, { ssr: false }); +const MobileAssetsList = dynamic(async () => (await import("~/components/mobile/MobileAssetsList")).MobileAssetsList, { + ssr: false, +}); + +const UserPositions = dynamic(async () => (await import("~/components/desktop/UserPositions")).UserPositions, { ssr: false, }); -const AssetsList = dynamic(async () => (await import("~/components/desktop/AssetsList")).AssetsList, { ssr: false }); -const UserPositions = dynamic(async () => (await import("~/components/desktop/UserPositions")).UserPositions, { ssr: false }); const Home = () => { const { walletAddress, wallet, isOverride } = useWalletContext(); @@ -60,33 +75,37 @@ const Home = () => { return ( <> - - -
- {walletAddress && selectedAccount && isOverride && ( - - )} - {walletAddress && marginfiAccountCount > 1 && ( - - )} + + +
+ {walletAddress && selectedAccount && isOverride && ( + + )} + {walletAddress && marginfiAccountCount > 1 && ( + + )} - -
-
- - {walletAddress && } -
- -
+ +
+
+ + {walletAddress && } +
+ +
- - LETS GOOOOO - + + LETS GOOOOO BIG +
+ + +
+
); }; diff --git a/apps/marginfi-v2-ui/src/pages/lip.tsx b/apps/marginfi-v2-ui/src/pages/lip.tsx index 5fe2c348ff..49bcca8277 100644 --- a/apps/marginfi-v2-ui/src/pages/lip.tsx +++ b/apps/marginfi-v2-ui/src/pages/lip.tsx @@ -1,7 +1,7 @@ import { PageHeader } from "~/components/desktop/PageHeader"; import { CampaignWizard } from "~/components/desktop/CampaignWizard"; import { LipClientProvider } from "~/context"; -import { useWalletContext } from "~/components/common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; const LIP = () => { const { connected } = useWalletContext(); diff --git a/apps/marginfi-v2-ui/src/pages/points.tsx b/apps/marginfi-v2-ui/src/pages/points.tsx index 542bb9cb35..f33ad4cf50 100644 --- a/apps/marginfi-v2-ui/src/pages/points.tsx +++ b/apps/marginfi-v2-ui/src/pages/points.tsx @@ -31,7 +31,7 @@ import { toast } from "react-toastify"; import { useUserProfileStore } from "~/store"; import { LeaderboardRow, fetchLeaderboardData, firebaseApi } from "@mrgnlabs/marginfi-v2-ui-state"; import { numeralFormatter, groupedNumberFormatterDyn } from "@mrgnlabs/mrgn-common"; -import { useWalletContext } from "~/components/common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( diff --git a/apps/marginfi-v2-ui/src/pages/swap.tsx b/apps/marginfi-v2-ui/src/pages/swap.tsx index 6c0b12455e..0ae11ea979 100644 --- a/apps/marginfi-v2-ui/src/pages/swap.tsx +++ b/apps/marginfi-v2-ui/src/pages/swap.tsx @@ -3,7 +3,7 @@ import { useEffect } from "react"; import config from "~/config"; import { PageHeaderSwap } from "~/components/desktop/PageHeader"; -import { useWalletContext } from "~/components/common/useWalletContext"; +import { useWalletContext } from "~/hooks/useWalletContext"; const SwapPage = () => { const { walletContextState } = useWalletContext(); diff --git a/apps/marginfi-v2-ui/src/utils/index.ts b/apps/marginfi-v2-ui/src/utils/index.ts index b3dc1d121a..638495d45e 100644 --- a/apps/marginfi-v2-ui/src/utils/index.ts +++ b/apps/marginfi-v2-ui/src/utils/index.ts @@ -1,40 +1,3 @@ -import { PublicKey, TransactionInstruction } from "@solana/web3.js"; -import BN from "bn.js"; -import { TOKEN_PROGRAM_ID } from "@mrgnlabs/mrgn-common"; -import { ActiveBankInfo } from "@mrgnlabs/marginfi-v2-ui-state"; - -// ================ development utils ================ - -export const FAUCET_PROGRAM_ID = new PublicKey("4bXpkKSV8swHSnwqtzuboGPaPDeEgAn4Vt8GfarV5rZt"); - -export function makeAirdropCollateralIx( - amount: number, - mint: PublicKey, - tokenAccount: PublicKey, - faucet: PublicKey -): TransactionInstruction { - const [faucetPda] = PublicKey.findProgramAddressSync([Buffer.from("faucet")], FAUCET_PROGRAM_ID); - - const keys = [ - { pubkey: faucetPda, isSigner: false, isWritable: false }, - { pubkey: mint, isSigner: false, isWritable: true }, - { pubkey: tokenAccount, isSigner: false, isWritable: true }, - { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, - { pubkey: faucet, isSigner: false, isWritable: false }, - ]; - - return new TransactionInstruction({ - programId: FAUCET_PROGRAM_ID, - data: Buffer.from([1, ...new BN(amount).toArray("le", 8)]), - keys, - }); -} - -export function isWholePosition(activeBankInfo: ActiveBankInfo, amount: number): boolean { - const positionTokenAmount = - Math.floor(activeBankInfo.position.amount * Math.pow(10, activeBankInfo.info.state.mintDecimals)) / - Math.pow(10, activeBankInfo.info.state.mintDecimals); - return amount >= positionTokenAmount; -} - export { OKXWalletAdapter } from "./OKXWalletAdapter"; +export * from "./mrgnActions"; +export * from "./mrgnUtils"; diff --git a/apps/marginfi-v2-ui/src/utils/mrgnActions.ts b/apps/marginfi-v2-ui/src/utils/mrgnActions.ts new file mode 100644 index 0000000000..7d9556cfcb --- /dev/null +++ b/apps/marginfi-v2-ui/src/utils/mrgnActions.ts @@ -0,0 +1,196 @@ +import { MarginfiAccountWrapper, MarginfiClient, MarginfiConfig } from "@mrgnlabs/marginfi-client-v2"; +import { + ExtendedBankInfo, + Emissions, + FEE_MARGIN, + ActionType, + getCurrentAction, + ExtendedBankMetadata, +} from "@mrgnlabs/marginfi-v2-ui-state"; +import { toast } from "react-toastify"; +import { isWholePosition } from "./mrgnUtils"; + +const CLOSE_BALANCE_TOAST_ID = "close-balance"; +const BORROW_OR_LEND_TOAST_ID = "borrow-or-lend"; + +export const closeBalance = async ({ + bank, + marginfiAccount, +}: { + bank: ExtendedBankInfo; + marginfiAccount?: MarginfiAccountWrapper; +}) => { + if (!marginfiAccount) { + toast.error("marginfi account not ready."); + throw new Error("marginfi account not ready."); + } + + if (!bank.isActive) { + toast.error("no position to close."); + throw new Error("no position to close."); + } + + toast.loading("Closing dust balance", { + toastId: CLOSE_BALANCE_TOAST_ID, + }); + + try { + if (bank.position.isLending) { + await marginfiAccount.withdraw(0, bank.address, true); + } else { + await marginfiAccount.repay(0, bank.address, true); + } + toast.update(CLOSE_BALANCE_TOAST_ID, { + render: "Closing 👍", + type: toast.TYPE.SUCCESS, + autoClose: 2000, + isLoading: false, + }); + } catch (error: any) { + toast.update(CLOSE_BALANCE_TOAST_ID, { + render: `Error while closing balance: ${error.message}`, + type: toast.TYPE.ERROR, + autoClose: 5000, + isLoading: false, + }); + console.log(`Error while closing balance`); + console.log(error); + } +}; + +export const borrowOrLend = async ({ + mfiClient, + currentAction, + bank, + borrowOrLendAmount, + nativeSolBalance, + marginfiAccount, +}: { + mfiClient: MarginfiClient; + bank: ExtendedBankInfo; + currentAction: ActionType | "Connect"; + borrowOrLendAmount: number; + nativeSolBalance: number; + marginfiAccount?: MarginfiAccountWrapper; +}) => { + if (mfiClient === null) throw Error("Marginfi client not ready"); + + if (currentAction === ActionType.Deposit && bank.info.state.totalDeposits >= bank.info.rawBank.config.depositLimit) { + toast.error( + `${bank.meta.tokenSymbol} deposit limit has been been reached. Additional deposits are not currently available.` + ); + return; + } + + if (currentAction === ActionType.Borrow && bank.info.state.totalBorrows >= bank.info.rawBank.config.borrowLimit) { + toast.error( + `${bank.meta.tokenSymbol} borrow limit has been been reached. Additional borrows are not currently available.` + ); + return; + } + + if (currentAction === ActionType.Deposit && bank.userInfo.maxDeposit === 0) { + toast.error(`You don't have any ${bank.meta.tokenSymbol} to lend in your wallet.`); + return; + } + + if (currentAction === ActionType.Borrow && bank.userInfo.maxBorrow === 0) { + toast.error(`You cannot borrow any ${bank.meta.tokenSymbol} right now.`); + return; + } + + if (borrowOrLendAmount <= 0) { + toast.error("Please enter an amount over 0."); + return; + } + + let _marginfiAccount = marginfiAccount; + + if (nativeSolBalance < FEE_MARGIN) { + toast.error("Not enough sol for fee."); + return; + } + + // -------- Create marginfi account if needed + try { + if (!_marginfiAccount) { + if (currentAction !== ActionType.Deposit) { + toast.error("An account is required for anything operation except deposit."); + return; + } + + toast.loading("Creating account", { + toastId: BORROW_OR_LEND_TOAST_ID, + }); + + _marginfiAccount = await mfiClient.createMarginfiAccount(); + toast.update(BORROW_OR_LEND_TOAST_ID, { + render: `${currentAction + "ing"} ${borrowOrLendAmount} ${bank.meta.tokenSymbol}`, + }); + } + } catch (error: any) { + toast.update(BORROW_OR_LEND_TOAST_ID, { + render: `Error while ${currentAction + "ing"}: ${error.message}`, + type: toast.TYPE.ERROR, + autoClose: 5000, + isLoading: false, + }); + console.log(`Error while ${currentAction + "ing"}`); + console.log(error); + return; + } + + // -------- Perform relevant operation + try { + if (currentAction === ActionType.Deposit) { + await _marginfiAccount.deposit(borrowOrLendAmount, bank.address); + + toast.update(BORROW_OR_LEND_TOAST_ID, { + render: `${currentAction + "ing"} ${borrowOrLendAmount} ${bank.meta.tokenSymbol} 👍`, + type: toast.TYPE.SUCCESS, + autoClose: 2000, + isLoading: false, + }); + } + + toast.loading(`${currentAction + "ing"} ${borrowOrLendAmount} ${bank.meta.tokenSymbol}`, { + toastId: BORROW_OR_LEND_TOAST_ID, + }); + if (_marginfiAccount === null) { + // noinspection ExceptionCaughtLocallyJS + throw Error("Marginfi account not ready"); + } + + if (currentAction === ActionType.Borrow) { + await _marginfiAccount.borrow(borrowOrLendAmount, bank.address); + } else if (currentAction === ActionType.Repay) { + await _marginfiAccount.repay( + borrowOrLendAmount, + bank.address, + bank.isActive && isWholePosition(bank, borrowOrLendAmount) + ); + } else if (currentAction === ActionType.Withdraw) { + await _marginfiAccount.withdraw( + borrowOrLendAmount, + bank.address, + bank.isActive && isWholePosition(bank, borrowOrLendAmount) + ); + } + + toast.update(BORROW_OR_LEND_TOAST_ID, { + render: `${currentAction + "ing"} ${borrowOrLendAmount} ${bank.meta.tokenSymbol} 👍`, + type: toast.TYPE.SUCCESS, + autoClose: 2000, + isLoading: false, + }); + } catch (error: any) { + toast.update(BORROW_OR_LEND_TOAST_ID, { + render: `Error while ${currentAction + "ing"}: ${error.message}`, + type: toast.TYPE.ERROR, + autoClose: 5000, + isLoading: false, + }); + console.log(`Error while ${currentAction + "ing"}`); + console.log(error); + } +}; diff --git a/apps/marginfi-v2-ui/src/utils/mrgnUtils.ts b/apps/marginfi-v2-ui/src/utils/mrgnUtils.ts new file mode 100644 index 0000000000..c72e05fdca --- /dev/null +++ b/apps/marginfi-v2-ui/src/utils/mrgnUtils.ts @@ -0,0 +1,38 @@ +import { PublicKey, TransactionInstruction } from "@solana/web3.js"; +import BN from "bn.js"; +import { TOKEN_PROGRAM_ID } from "@mrgnlabs/mrgn-common"; +import { ActiveBankInfo } from "@mrgnlabs/marginfi-v2-ui-state"; + +// ================ development utils ================ + +export const FAUCET_PROGRAM_ID = new PublicKey("4bXpkKSV8swHSnwqtzuboGPaPDeEgAn4Vt8GfarV5rZt"); + +export function makeAirdropCollateralIx( + amount: number, + mint: PublicKey, + tokenAccount: PublicKey, + faucet: PublicKey +): TransactionInstruction { + const [faucetPda] = PublicKey.findProgramAddressSync([Buffer.from("faucet")], FAUCET_PROGRAM_ID); + + const keys = [ + { pubkey: faucetPda, isSigner: false, isWritable: false }, + { pubkey: mint, isSigner: false, isWritable: true }, + { pubkey: tokenAccount, isSigner: false, isWritable: true }, + { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, + { pubkey: faucet, isSigner: false, isWritable: false }, + ]; + + return new TransactionInstruction({ + programId: FAUCET_PROGRAM_ID, + data: Buffer.from([1, ...new BN(amount).toArray("le", 8)]), + keys, + }); +} + +export function isWholePosition(activeBankInfo: ActiveBankInfo, amount: number): boolean { + const positionTokenAmount = + Math.floor(activeBankInfo.position.amount * Math.pow(10, activeBankInfo.info.state.mintDecimals)) / + Math.pow(10, activeBankInfo.info.state.mintDecimals); + return amount >= positionTokenAmount; +} diff --git a/apps/marginfi-v2-ui/tailwind.config.js b/apps/marginfi-v2-ui/tailwind.config.js index 44786fb23f..944cc04293 100644 --- a/apps/marginfi-v2-ui/tailwind.config.js +++ b/apps/marginfi-v2-ui/tailwind.config.js @@ -10,7 +10,7 @@ module.exports = { backgroundImage: { "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", "jup-gradient-colors": "linear-gradient(to right, #A0F0F8, #EEAC55)", - "mayan-gradient-colors": "linear-gradient(90deg, #5768BD 0.11%, #FFFFFF 100%)" + "mayan-gradient-colors": "linear-gradient(90deg, #5768BD 0.11%, #FFFFFF 100%)", }, borderImage: { SOL: "linear-gradient(to top right, #9945FF, #19FB9B)", @@ -28,6 +28,9 @@ module.exports = { colors: { "usd-equiv": "rgba(113, 119, 126, 0.3)", "btn-light": "rgb(227, 227, 227)", + success: "#75ba80", + warning: "#daa204)", + error: "#e07d6f", }, }, fontFamily: { @@ -42,7 +45,7 @@ module.exports = { }, }, plugins: [ - plugin(function({ addUtilities }) { + plugin(function ({ addUtilities }) { addUtilities({ ".invisible-scroll": { "content-visibility": "auto", diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardStats.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardStats.tsx index bce0af6a5f..619564097e 100644 --- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardStats.tsx +++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardStats.tsx @@ -15,11 +15,11 @@ type Props = { export function PoolCardStats({ bank, isInLendingMode, nativeSolBalance, bankFilled }: Props) { const assetWeight = useMemo(() => { - if (bank.info.rawBank.config.assetWeightMaint.toNumber() <= 0) { + if (bank.info.rawBank.config.assetWeightInit.toNumber() <= 0) { return "-"; } return isInLendingMode - ? (bank.info.rawBank.config.assetWeightMaint.toNumber() * 100).toFixed(0) + "%" + ? (bank.info.rawBank.config.assetWeightInit.toNumber() * 100).toFixed(0) + "%" : ((1 / bank.info.rawBank.config.liabilityWeightInit.toNumber()) * 100).toFixed(0) + "%"; }, [isInLendingMode, bank]); From e68176641618085d04ee048eff265d58dd38cae0 Mon Sep 17 00:00:00 2001 From: Kobe Leenders Date: Fri, 8 Sep 2023 11:00:07 +0200 Subject: [PATCH 003/351] fix(mfi-v2-ui): build error --- .../MobileAssetsList/AssetCard/AssetCard.tsx | 30 +++++++++++++++++ .../AssetCard/AssetCardStats.tsx | 32 +++++++++++++++---- apps/marginfi-v2-ui/src/utils/mrgnActions.ts | 6 ++-- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx index 5298fc1bd6..c106b7bcb8 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx @@ -22,6 +22,7 @@ import { borrowOrLend, closeBalance } from "~/utils"; import { useWalletContext } from "~/hooks/useWalletContext"; import { useAssetItemData } from "~/hooks/useAssetItemData"; import { HtmlTooltip } from "~/components/common/HtmlTooltip"; +import { AssetCardStats } from "./AssetCardStats"; export const AssetCard: FC<{ bank: ExtendedBankInfo; @@ -45,6 +46,25 @@ export const AssetCard: FC<{ }) => { const { rateAP, assetWeight, isBankFilled, isBankHigh, bankFilled } = useAssetItemData({ bank, isInLendingMode }); + const totalDepositsOrBorrows = useMemo( + () => + isInLendingMode + ? bank.info.state.totalDeposits + : Math.max( + 0, + Math.min(bank.info.state.totalDeposits, bank.info.rawBank.config.borrowLimit) - bank.info.state.totalBorrows + ), + [isInLendingMode, bank.info] + ); + + const userBalance = useMemo( + () => + bank.info.state.mint.equals(WSOL_MINT) + ? bank.userInfo.tokenAccount.balance + nativeSolBalance + : bank.userInfo.tokenAccount.balance, + [bank.info.state.mint, bank.userInfo.tokenAccount, nativeSolBalance] + ); + return (
@@ -63,6 +83,16 @@ export const AssetCard: FC<{
{rateAP.concat(...[" ", isInLendingMode ? "APY" : "APR"])}
+
); }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx index 62a941a620..6fb1903b14 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx @@ -18,12 +18,26 @@ import { import { ExtendedBankInfo, ActionType, getCurrentAction, ExtendedBankMetadata } from "@mrgnlabs/marginfi-v2-ui-state"; import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2"; -export const AssetStats: FC<{ +export const AssetCardStats: FC<{ bank: ExtendedBankInfo; assetWeight: string; + totalDepositsOrBorrows: number; + userBalance: number; + isBankFilled: boolean; + isBankHigh: boolean; + bankFilled: number; isInLendingMode: boolean; - userBalance: string; -}> = ({ bank, assetWeight, isInLendingMode, userBalance }) => { +}> = ({ + bank, + assetWeight, + totalDepositsOrBorrows, + userBalance, + isBankFilled, + isBankHigh, + bankFilled, + isInLendingMode, +}) => { + console.log({ totalDepositsOrBorrows }); return (
@@ -33,10 +47,14 @@ export const AssetStats: FC<{ {/* TODO: Add seperator */}
{isInLendingMode ? "Deposits" : "Available"}
-
{0}
- {/* {isHigh && ( -
{percentFormatter.format(bankFilled)}
- )} */} +
{numeralFormatter(totalDepositsOrBorrows)}
+ {isBankHigh && ( +
+ {percentFormatter.format( + (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) / bankFilled + )} +
+ )}
{/* TODO: Add seperator */}
diff --git a/apps/marginfi-v2-ui/src/utils/mrgnActions.ts b/apps/marginfi-v2-ui/src/utils/mrgnActions.ts index 7d9556cfcb..3ea812020a 100644 --- a/apps/marginfi-v2-ui/src/utils/mrgnActions.ts +++ b/apps/marginfi-v2-ui/src/utils/mrgnActions.ts @@ -18,7 +18,7 @@ export const closeBalance = async ({ marginfiAccount, }: { bank: ExtendedBankInfo; - marginfiAccount?: MarginfiAccountWrapper; + marginfiAccount: MarginfiAccountWrapper | null; }) => { if (!marginfiAccount) { toast.error("marginfi account not ready."); @@ -66,12 +66,12 @@ export const borrowOrLend = async ({ nativeSolBalance, marginfiAccount, }: { - mfiClient: MarginfiClient; + mfiClient: MarginfiClient | null; bank: ExtendedBankInfo; currentAction: ActionType | "Connect"; borrowOrLendAmount: number; nativeSolBalance: number; - marginfiAccount?: MarginfiAccountWrapper; + marginfiAccount: MarginfiAccountWrapper | null; }) => { if (mfiClient === null) throw Error("Marginfi client not ready"); From 4b9f8596c1317d8a421f9d55e2657e7ad26b82f6 Mon Sep 17 00:00:00 2001 From: Kobe Leenders Date: Fri, 8 Sep 2023 20:59:37 +0200 Subject: [PATCH 004/351] feat(mfi-v2-ui): mrgnlend mobile view --- .../common/AccountSummary/GlobalStats.tsx | 5 +- .../common/AccountSummary/UserStats.tsx | 430 +++++++++--------- .../AssetList}/AssetRowAction.tsx | 2 +- .../AssetList}/AssetRowInputBox.tsx | 0 .../src/components/common/AssetList/index.ts | 2 + .../src/components/common/HtmlTooltip.tsx | 15 - .../Tooltip.tsx => common/MrgnTooltip.tsx} | 0 .../desktop/AssetsList/AssetRow/AssetRow.tsx | 21 +- .../desktop/AssetsList/AssetsList.tsx | 52 ++- .../DesktopAccountSummary.tsx | 16 +- .../desktop/UserPositions/UserPositions.tsx | 27 +- .../MobileAccountSummary.tsx | 37 +- .../MobileAssetsList/AssetCard/AssetCard.tsx | 101 ++-- .../AssetCard/AssetCardActions.tsx | 80 ++++ .../AssetCard/AssetCardHeader.tsx | 59 +++ .../AssetCard/AssetCardPosition.tsx | 44 ++ .../AssetCard/AssetCardStats.tsx | 98 ++-- .../MobileAssetsList/MobileAssetsList.tsx | 110 +++-- apps/marginfi-v2-ui/src/pages/index.tsx | 2 +- apps/marginfi-v2-ui/tailwind.config.js | 2 +- apps/marginfi-v2-ui/tsconfig.json | 2 + 21 files changed, 702 insertions(+), 403 deletions(-) rename apps/marginfi-v2-ui/src/components/{desktop/AssetsList/AssetRow => common/AssetList}/AssetRowAction.tsx (100%) rename apps/marginfi-v2-ui/src/components/{desktop/AssetsList/AssetRow => common/AssetList}/AssetRowInputBox.tsx (100%) delete mode 100644 apps/marginfi-v2-ui/src/components/common/HtmlTooltip.tsx rename apps/marginfi-v2-ui/src/components/{desktop/Tooltip.tsx => common/MrgnTooltip.tsx} (100%) create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardActions.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardHeader.tsx create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardPosition.tsx diff --git a/apps/marginfi-v2-ui/src/components/common/AccountSummary/GlobalStats.tsx b/apps/marginfi-v2-ui/src/components/common/AccountSummary/GlobalStats.tsx index 02d898fe9a..b24f0ef63e 100644 --- a/apps/marginfi-v2-ui/src/components/common/AccountSummary/GlobalStats.tsx +++ b/apps/marginfi-v2-ui/src/components/common/AccountSummary/GlobalStats.tsx @@ -1,10 +1,11 @@ import { FC } from "react"; import { Typography, Skeleton } from "@mui/material"; -import { numeralFormatter } from "@mrgnlabs/mrgn-common"; import Image from "next/image"; import Link from "next/link"; -import { MrgnTooltip } from "~/components/desktop/Tooltip"; +import { numeralFormatter } from "@mrgnlabs/mrgn-common"; + +import { MrgnTooltip } from "~/components/common/MrgnTooltip"; import styles from "./style.module.css"; diff --git a/apps/marginfi-v2-ui/src/components/common/AccountSummary/UserStats.tsx b/apps/marginfi-v2-ui/src/components/common/AccountSummary/UserStats.tsx index a735829781..65cbf7dde2 100644 --- a/apps/marginfi-v2-ui/src/components/common/AccountSummary/UserStats.tsx +++ b/apps/marginfi-v2-ui/src/components/common/AccountSummary/UserStats.tsx @@ -1,11 +1,12 @@ import React, { FC, useMemo } from "react"; -import { AccountSummary } from "@mrgnlabs/marginfi-v2-ui-state"; -import { usdFormatter, numeralFormatter, usdFormatterDyn, percentFormatter } from "@mrgnlabs/mrgn-common"; -import { Typography, Skeleton } from "@mui/material"; +import { Typography } from "@mui/material"; import Image from "next/image"; import Link from "next/link"; -import { MrgnTooltip } from "~/components/desktop/Tooltip"; +import { AccountSummary } from "@mrgnlabs/marginfi-v2-ui-state"; +import { usdFormatter, numeralFormatter, usdFormatterDyn, percentFormatter } from "@mrgnlabs/mrgn-common"; + +import { MrgnTooltip } from "~/components/common/MrgnTooltip"; import styles from "./style.module.css"; @@ -34,240 +35,245 @@ const UserStats: FC = ({ accountSummary, healthFactor }) => { }, [healthFactor]); return ( -
- Your account -
-
-
-
- - Account -
- {accountSummary && ( - - - Your account - -
- {`Without price bias, your account balance is ${usdFormatter.format( - accountSummary.balanceUnbiased - )}. With bias, your account balance is ${usdFormatter.format(accountSummary.balance)}.`} -
- - Learn why price bias matters. - - - } - placement="top" - > +
+
+
+
+ + Account +
+ {accountSummary && ( + + + Your account + +
+ {`Without price bias, your account balance is ${usdFormatter.format( + accountSummary.balanceUnbiased + )}. With bias, your account balance is ${usdFormatter.format(accountSummary.balance)}.`} +
+ + Learn why price bias matters. + + + } + placement="top" + > +
info - - )} -
- - - {accountSummary ? ( - <> -
{`$${numeralFormatter(accountSummary.balanceUnbiased)}`}
- -
- {Math.round(accountSummary.balanceUnbiased) > 10000 - ? usdFormatterDyn.format(Math.round(accountSummary.balanceUnbiased)) - : usdFormatter.format(accountSummary.balanceUnbiased)}
- -
{usdFormatter.format(accountSummary.balanceUnbiased)}
- - ) : ( - "-" +
)} - -
-
-
- -
-
-
- - Supplying -
- {accountSummary && ( - - - How much are you lending? - -
- {`Your assets are worth ${usdFormatter.format( - accountSummary.lendingAmountUnbiased - )} without price bias and ${usdFormatter.format( - accountSummary.lendingAmount - )} with price bias.`} -
- - Learn why price bias matters. - - - } - placement="top" - > - info -
- )} -
-
- - {accountSummary ? ( - <> -
{`$${numeralFormatter(accountSummary.lendingAmountUnbiased)}`}
+
+ + + {accountSummary ? ( + <> +
{`$${numeralFormatter(accountSummary.balanceUnbiased)}`}
-
- {Math.round(accountSummary.lendingAmountUnbiased) > 10000 - ? usdFormatterDyn.format(Math.round(accountSummary.lendingAmountUnbiased)) - : usdFormatter.format(accountSummary.lendingAmountUnbiased)} -
+
+ {Math.round(accountSummary.balanceUnbiased) > 10000 + ? usdFormatterDyn.format(Math.round(accountSummary.balanceUnbiased)) + : usdFormatter.format(accountSummary.balanceUnbiased)} +
-
{usdFormatter.format(accountSummary.lendingAmountUnbiased)}
- - ) : ( - "-" - )} -
-
+
{usdFormatter.format(accountSummary.balanceUnbiased)}
+ + ) : ( + "-" + )} +
- -
-
- - Borrowing -
- {accountSummary && ( - - - How much are you borrowing? - -
- {`Your liabilities are worth ${usdFormatter.format( - accountSummary.borrowingAmountUnbiased - )} without price bias and ${usdFormatter.format( - accountSummary.borrowingAmount - )} with price bias.`} -
- - Learn why price bias matters. - - - } - placement="top" - > +
+ +
+
+ + Supplying +
+ {accountSummary && ( + + + How much are you lending? + +
+ {`Your assets are worth ${usdFormatter.format( + accountSummary.lendingAmountUnbiased + )} without price bias and ${usdFormatter.format( + accountSummary.lendingAmount + )} with price bias.`} +
+ + Learn why price bias matters. + + + } + placement="top" + > +
info - - )} -
- - - {accountSummary ? ( - <> -
{`$${numeralFormatter(accountSummary.borrowingAmountUnbiased)}`}
- -
- {Math.round(accountSummary.borrowingAmountUnbiased) > 10000 - ? usdFormatterDyn.format(Math.round(accountSummary.borrowingAmountUnbiased)) - : usdFormatter.format(accountSummary.borrowingAmountUnbiased)}
- -
{usdFormatter.format(accountSummary.borrowingAmountUnbiased)}
- - ) : ( - "-" +
)} - -
+
+ + + {accountSummary ? ( + <> +
{`$${numeralFormatter(accountSummary.lendingAmountUnbiased)}`}
+ +
+ {Math.round(accountSummary.lendingAmountUnbiased) > 10000 + ? usdFormatterDyn.format(Math.round(accountSummary.lendingAmountUnbiased)) + : usdFormatter.format(accountSummary.lendingAmountUnbiased)} +
+ +
{usdFormatter.format(accountSummary.lendingAmountUnbiased)}
+ + ) : ( + "-" + )} +
- -
-
- - Health -
- {accountSummary && ( - - - Health Factor - -
-
- Health factor is based off of price biased and weighted asset and liability - values. -
-
The formula is:
-
{"(assets - liabilities) / (assets)"}
-
Your math is:
-
{`(${usdFormatter.format( - accountSummary.lendingAmountWithBiasAndWeighted - )} - ${usdFormatter.format( - accountSummary.borrowingAmountWithBiasAndWeighted - )}) / (${usdFormatter.format(accountSummary.lendingAmountWithBiasAndWeighted)})`}
-
- - } - placement="top" - > +
+ +
+
+ + Borrowing +
+ {accountSummary && ( + + + How much are you borrowing? + +
+ {`Your liabilities are worth ${usdFormatter.format( + accountSummary.borrowingAmountUnbiased + )} without price bias and ${usdFormatter.format( + accountSummary.borrowingAmount + )} with price bias.`} +
+ + Learn why price bias matters. + + + } + placement="top" + > +
info - - )} -
-
- - - {healthFactor ? percentFormatter.format(healthFactor) : "-"} - -
+
+ + )} +
+
+ + {accountSummary ? ( + <> +
{`$${numeralFormatter(accountSummary.borrowingAmountUnbiased)}`}
+ +
+ {Math.round(accountSummary.borrowingAmountUnbiased) > 10000 + ? usdFormatterDyn.format(Math.round(accountSummary.borrowingAmountUnbiased)) + : usdFormatter.format(accountSummary.borrowingAmountUnbiased)} +
+ +
{usdFormatter.format(accountSummary.borrowingAmountUnbiased)}
+ + ) : ( + "-" + )} +
- -
-
- - Free -
+
+ +
+
+ + Health +
+ {accountSummary && ( - Free Collateral + Health Factor
- Free collateral indicates how much of your collateral is available to open additional - borrows or withdraw existing collateral. + Health factor is based off of price biased and weighted asset and liability + values.
-
It is computed from the weighted deposits and weighted borrows.
+
The formula is:
+
{"(assets - liabilities) / (assets)"}
+
Your math is:
+
{`(${usdFormatter.format( + accountSummary.lendingAmountWithBiasAndWeighted + )} - ${usdFormatter.format( + accountSummary.borrowingAmountWithBiasAndWeighted + )}) / (${usdFormatter.format(accountSummary.lendingAmountWithBiasAndWeighted)})`}
} placement="top" > - info +
+
+ info +
+
-
-
-
- = 0 ? "#fff" : "#B8B45F"} - className="font-aeonik font-[500] text-lg md:text-xl" - component="div" - > - {accountSummary ? usdFormatter.format(accountSummary.signedFreeCollateral) : "-"} - -
+ )} +
+
+
+ + {healthFactor ? percentFormatter.format(healthFactor) : "-"} + +
+
+ +
+
+ + Free +
+ + + Free Collateral + +
+
+ Free collateral indicates how much of your collateral is available to open additional borrows + or withdraw existing collateral. +
+
It is computed from the weighted deposits and weighted borrows.
+
+ + } + placement="top" + > + info +
+
+
+
+ = 0 ? "#fff" : "#B8B45F"} + className="font-aeonik font-[500] text-lg md:text-xl" + component="div" + > + {accountSummary ? usdFormatter.format(accountSummary.signedFreeCollateral) : "-"} +
diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowAction.tsx b/apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowAction.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowAction.tsx rename to apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowAction.tsx index 9b3786bd03..4a91eec146 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowAction.tsx +++ b/apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowAction.tsx @@ -1,5 +1,5 @@ -import { Button, ButtonProps } from "@mui/material"; import { FC, ReactNode } from "react"; +import { Button, ButtonProps } from "@mui/material"; interface AssetRowActionProps extends ButtonProps { children?: ReactNode; diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowInputBox.tsx b/apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowInputBox.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRowInputBox.tsx rename to apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowInputBox.tsx diff --git a/apps/marginfi-v2-ui/src/components/common/AssetList/index.ts b/apps/marginfi-v2-ui/src/components/common/AssetList/index.ts index 8442d9cd65..b587432a91 100644 --- a/apps/marginfi-v2-ui/src/components/common/AssetList/index.ts +++ b/apps/marginfi-v2-ui/src/components/common/AssetList/index.ts @@ -1 +1,3 @@ export * from "./BorrowLendToggle"; +export * from "./AssetRowAction"; +export * from "./AssetRowInputBox"; diff --git a/apps/marginfi-v2-ui/src/components/common/HtmlTooltip.tsx b/apps/marginfi-v2-ui/src/components/common/HtmlTooltip.tsx deleted file mode 100644 index 15c924d0bc..0000000000 --- a/apps/marginfi-v2-ui/src/components/common/HtmlTooltip.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react"; -import { styled } from "@mui/material/styles"; -import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; - -export const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( - -))(({ theme }) => ({ - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: "rgb(227, 227, 227)", - color: "rgba(0, 0, 0, 0.87)", - maxWidth: 220, - fontSize: theme.typography.pxToRem(12), - border: "1px solid #dadde9", - }, -})); diff --git a/apps/marginfi-v2-ui/src/components/desktop/Tooltip.tsx b/apps/marginfi-v2-ui/src/components/common/MrgnTooltip.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/desktop/Tooltip.tsx rename to apps/marginfi-v2-ui/src/components/common/MrgnTooltip.tsx diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx index 33dcd16122..13cc94b65d 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx @@ -1,8 +1,7 @@ import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; import Image from "next/image"; import { TableCell, TableRow } from "@mui/material"; -import { styled } from "@mui/material/styles"; -import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; +import Tooltip from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; import { useMrgnlendStore, useUserProfileStore } from "~/store"; import Badge from "@mui/material/Badge"; @@ -21,10 +20,8 @@ import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2" import { borrowOrLend, closeBalance } from "~/utils"; import { useWalletContext } from "~/hooks/useWalletContext"; import { useAssetItemData } from "~/hooks/useAssetItemData"; -import { HtmlTooltip } from "~/components/common/HtmlTooltip"; - -import { AssetRowInputBox } from "./AssetRowInputBox"; -import { AssetRowAction } from "./AssetRowAction"; +import { MrgnTooltip } from "~/components/common/MrgnTooltip"; +import { AssetRowInputBox, AssetRowAction } from "~/components/common/AssetList"; const AssetRow: FC<{ bank: ExtendedBankInfo; @@ -156,7 +153,7 @@ const AssetRow: FC<{ align="right" style={{ fontWeight: 300 }} > - @@ -191,7 +188,7 @@ const AssetRow: FC<{ : usdFormatter.format(bank.info.state.price) : `$${bank.info.state.price.toExponential(2)}`} - + {bank.meta.tokenSymbol === "UXD" && isInLendingMode && (
- @@ -222,7 +219,7 @@ const AssetRow: FC<{ placement="left" > info - +
)}
- @@ -304,7 +301,7 @@ const AssetRow: FC<{ ) )} - + {/*******************************/} diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx index b03c4d3443..87c0d92618 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx @@ -2,8 +2,6 @@ import React, { FC, useEffect, useRef, useState } from "react"; import Image from "next/image"; import { useHotkeys } from "react-hotkeys-hook"; import { Card, Table, TableHead, TableBody, TableContainer, TableCell } from "@mui/material"; -import { styled } from "@mui/material/styles"; -import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; import { useMrgnlendStore, useUserProfileStore } from "~/store"; @@ -11,7 +9,7 @@ import { useWalletContext } from "~/hooks/useWalletContext"; import { BorrowLendToggle } from "~/components/common/AssetList/BorrowLendToggle"; import { LoadingAsset, AssetRow } from "./AssetRow"; -import { HtmlTooltip } from "~/components/common/HtmlTooltip"; +import { MrgnTooltip } from "~/components/common/MrgnTooltip"; const AssetsList: FC = () => { // const { selectedAccount, nativeSolBalance } = useStore(); @@ -124,19 +122,21 @@ const AssetsList: FC = () => { >
Price - Realtime prices - Powered by Pyth and Switchboard. + + Powered by Pyth and Switchboard. + } placement="top" > info - +
{ >
{isInLendingMode ? "APY" : "APR"} - @@ -162,7 +162,7 @@ const AssetsList: FC = () => { placement="top" > info - +
{ >
{isInLendingMode ? "Weight" : "LTV"} - {isInLendingMode ? "Weight" : "LTV"} - {isInLendingMode - ? "How much your assets count for collateral, relative to their USD value. The higher the weight, the more collateral you can borrow against it." - : "How much you can borrow against your free collateral. The higher the LTV, the more you can borrow against your free collateral."} + + {isInLendingMode + ? "How much your assets count for collateral, relative to their USD value. The higher the weight, the more collateral you can borrow against it." + : "How much you can borrow against your free collateral. The higher the LTV, the more you can borrow against your free collateral."} + } placement="top" > info - +
{ >
{isInLendingMode ? "Deposits" : "Available"} - {isInLendingMode ? "Total deposits" : "Total available"} - {isInLendingMode - ? "Total marginfi deposits for each asset. Everything is denominated in native tokens." - : "The amount of tokens available to borrow for each asset. Calculated as the minimum of the asset's borrow limit and available liquidity that has not yet been borrowed."} + + {isInLendingMode + ? "Total marginfi deposits for each asset. Everything is denominated in native tokens." + : "The amount of tokens available to borrow for each asset. Calculated as the minimum of the asset's borrow limit and available liquidity that has not yet been borrowed."} + } placement="top" > info - +
@@ -226,7 +230,7 @@ const AssetsList: FC = () => { >
Global limit - @@ -239,7 +243,7 @@ const AssetsList: FC = () => { placement="top" > info - +
)} @@ -252,7 +256,7 @@ const AssetsList: FC = () => { >
Utilization - @@ -265,7 +269,7 @@ const AssetsList: FC = () => { placement="top" > info - +
)} @@ -315,7 +319,7 @@ const AssetsList: FC = () => { Isolated pools - @@ -329,7 +333,7 @@ const AssetsList: FC = () => { placement="top" > info - +
{sortedBanks diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/DesktopAccountSummary.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/DesktopAccountSummary.tsx index 3e99c6f6fa..03ea07858f 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/DesktopAccountSummary.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopAccountSummary/DesktopAccountSummary.tsx @@ -1,6 +1,7 @@ import React, { FC } from "react"; -import { useMrgnlendStore } from "~/store"; import dynamic from "next/dynamic"; + +import { useMrgnlendStore } from "~/store"; import { useWalletContext } from "~/hooks/useWalletContext"; import { UserStats } from "~/components/common/AccountSummary"; @@ -19,7 +20,7 @@ const AccountSummary: FC = () => { return (
-
+
Global stats {
{connected && ( - +
+ Your account + +
)}
diff --git a/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx index 47d735e7b1..6ac8beb192 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/UserPositions/UserPositions.tsx @@ -1,13 +1,14 @@ import React, { FC, useMemo } from "react"; import { Card, Table, TableBody, TableContainer, TableHead, TableCell, Typography } from "@mui/material"; -import UserPositionRow from "./UserPositionRow"; -import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; -import { styled } from "@mui/material/styles"; import Image from "next/image"; import Link from "next/link"; -import { useMrgnlendStore } from "~/store"; + import { ActiveBankInfo } from "@mrgnlabs/marginfi-v2-ui-state"; -import { HtmlTooltip } from "~/components/common/HtmlTooltip"; + +import { useMrgnlendStore } from "~/store"; +import { MrgnTooltip } from "~/components/common/MrgnTooltip"; + +import UserPositionRow from "./UserPositionRow"; const UserPositions: FC = () => { const setIsRefreshingStore = useMrgnlendStore((state) => state.setIsRefreshingStore); @@ -60,7 +61,7 @@ const UserPositions: FC = () => { Wtd
- @@ -80,7 +81,7 @@ const UserPositions: FC = () => { placement="top" > info - +
@@ -92,7 +93,7 @@ const UserPositions: FC = () => { USD
- @@ -114,7 +115,7 @@ const UserPositions: FC = () => { placement="top" > info - +
@@ -169,7 +170,7 @@ const UserPositions: FC = () => { Wtd
- @@ -189,7 +190,7 @@ const UserPositions: FC = () => { placement="top" > info - +
@@ -201,7 +202,7 @@ const UserPositions: FC = () => { USD
- @@ -223,7 +224,7 @@ const UserPositions: FC = () => { placement="top" > info - +
diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/MobileAccountSummary.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/MobileAccountSummary.tsx index 91183d5353..c97597934d 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/MobileAccountSummary.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAccountSummary/MobileAccountSummary.tsx @@ -1,6 +1,7 @@ import React, { FC } from "react"; -import { useMrgnlendStore } from "~/store"; import dynamic from "next/dynamic"; + +import { useMrgnlendStore } from "~/store"; import { useWalletContext } from "~/hooks/useWalletContext"; import { UserStats } from "~/components/common/AccountSummary"; @@ -18,24 +19,30 @@ const AccountSummary: FC = () => { const { connected } = useWalletContext(); return ( -
-
- +
+
+
+ Global stats + +
{" "}
- {/*
+
{connected && ( - +
+ Your account + +
)} -
*/} +
); }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx index c106b7bcb8..6798772788 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx @@ -1,28 +1,19 @@ -import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; -import Image from "next/image"; -import { TableCell, TableRow } from "@mui/material"; -import { styled } from "@mui/material/styles"; -import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; -import Typography from "@mui/material/Typography"; -import { useMrgnlendStore, useUserProfileStore } from "~/store"; -import Badge from "@mui/material/Badge"; +import React, { FC, useCallback, useMemo } from "react"; -import { - WSOL_MINT, - groupedNumberFormatterDyn, - numeralFormatter, - percentFormatter, - uiToNative, - usdFormatter, -} from "@mrgnlabs/mrgn-common"; -import { ExtendedBankInfo, ActionType, getCurrentAction, ExtendedBankMetadata } from "@mrgnlabs/marginfi-v2-ui-state"; -import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2"; +import { WSOL_MINT } from "@mrgnlabs/mrgn-common"; +import { ExtendedBankInfo, ActionType, getCurrentAction } from "@mrgnlabs/marginfi-v2-ui-state"; +import { MarginfiAccountWrapper } from "@mrgnlabs/marginfi-client-v2"; +import { useMrgnlendStore } from "~/store"; import { borrowOrLend, closeBalance } from "~/utils"; import { useWalletContext } from "~/hooks/useWalletContext"; import { useAssetItemData } from "~/hooks/useAssetItemData"; -import { HtmlTooltip } from "~/components/common/HtmlTooltip"; + import { AssetCardStats } from "./AssetCardStats"; +import { AssetCardActions } from "./AssetCardActions"; + +import { AssetCardPosition } from "./AssetCardPosition"; +import { AssetCardHeader } from "./AssetCardHeader"; export const AssetCard: FC<{ bank: ExtendedBankInfo; @@ -45,7 +36,9 @@ export const AssetCard: FC<{ badgeContent, }) => { const { rateAP, assetWeight, isBankFilled, isBankHigh, bankFilled } = useAssetItemData({ bank, isInLendingMode }); - + const [mfiClient, fetchMrgnlendState] = useMrgnlendStore((state) => [state.marginfiClient, state.fetchMrgnlendState]); + const setIsRefreshingStore = useMrgnlendStore((state) => state.setIsRefreshingStore); + const { connected } = useWalletContext(); const totalDepositsOrBorrows = useMemo( () => isInLendingMode @@ -65,24 +58,46 @@ export const AssetCard: FC<{ [bank.info.state.mint, bank.userInfo.tokenAccount, nativeSolBalance] ); + const currentAction: ActionType | "Connect" = useMemo( + () => (connected ? getCurrentAction(isInLendingMode, bank) : "Connect"), + [connected, isInLendingMode, bank] + ); + + const handleCloseBalance = useCallback(async () => { + try { + closeBalance({ marginfiAccount, bank }); + } catch (error) { + return; + } + + try { + setIsRefreshingStore(true); + await fetchMrgnlendState(); + } catch (error: any) { + console.log("Error while reloading state"); + console.log(error); + } + }, [bank, marginfiAccount, fetchMrgnlendState, setIsRefreshingStore]); + + const handleBorrowOrLend = useCallback( + async (borrowOrLendAmount: number) => { + borrowOrLend({ mfiClient, currentAction, bank, borrowOrLendAmount, nativeSolBalance, marginfiAccount }); + + // -------- Refresh state + try { + setIsRefreshingStore(true); + await fetchMrgnlendState(); + } catch (error: any) { + console.log("Error while reloading state"); + console.log(error); + } + }, + [bank, currentAction, marginfiAccount, mfiClient, nativeSolBalance, fetchMrgnlendState, setIsRefreshingStore] + ); + return ( -
-
-
-
- {bank.meta.tokenLogoUri && ( - {bank.meta.tokenSymbol} - )} -
-
-
{bank.meta.tokenSymbol}
-
{usdFormatter.format(bank.info.state.price)}
-
-
-
-
{rateAP.concat(...[" ", isInLendingMode ? "APY" : "APR"])}
-
-
+
+ + /> + {bank.isActive && } + handleCloseBalance()} + onBorrowOrLend={(amount) => handleBorrowOrLend(amount)} + />
); }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardActions.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardActions.tsx new file mode 100644 index 0000000000..0e8134a4d0 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardActions.tsx @@ -0,0 +1,80 @@ +import React, { FC, useMemo, useState } from "react"; + +import { ExtendedBankInfo, ActionType } from "@mrgnlabs/marginfi-v2-ui-state"; +import { uiToNative } from "@mrgnlabs/mrgn-common"; + +import { AssetRowAction, AssetRowInputBox } from "~/components/common/AssetList"; +import { useWalletContext } from "~/hooks/useWalletContext"; + +export const AssetCardActions: FC<{ + bank: ExtendedBankInfo; + inputRefs: React.MutableRefObject>; + isBankFilled: boolean; + isInLendingMode: boolean; + currentAction: ActionType | "Connect"; + onCloseBalance: () => void; + onBorrowOrLend: (amount: number) => void; +}> = ({ bank, inputRefs, isBankFilled, currentAction, onCloseBalance, onBorrowOrLend }) => { + const { openWalletSelector } = useWalletContext(); + const [borrowOrLendAmount, setBorrowOrLendAmount] = useState(0); + + const maxAmount = useMemo(() => { + switch (currentAction) { + case ActionType.Deposit: + return bank.userInfo.maxDeposit; + case ActionType.Withdraw: + return bank.userInfo.maxWithdraw; + case ActionType.Borrow: + return bank.userInfo.maxBorrow; + case ActionType.Repay: + return bank.userInfo.maxRepay; + } + }, [bank.userInfo, currentAction]); + + const isDust = useMemo( + () => bank.isActive && uiToNative(bank.position.amount, bank.info.state.mintDecimals).isZero(), + [bank] + ); + + const isDisabled = useMemo( + () => + currentAction !== "Connect" && + ((isDust && uiToNative(bank.userInfo.tokenAccount.balance, bank.info.state.mintDecimals).isZero()) || + maxAmount === 0), + [currentAction, isBankFilled, isDust, maxAmount] + ); + + return ( + <> +
+ onBorrowOrLend(borrowOrLendAmount)} + /> + + currentAction === "Connect" + ? openWalletSelector() + : isDust + ? onCloseBalance() + : onBorrowOrLend(borrowOrLendAmount) + } + disabled={isDisabled} + > + {isDust ? "Close" : currentAction} + +
+ + ); +}; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardHeader.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardHeader.tsx new file mode 100644 index 0000000000..cdca305912 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardHeader.tsx @@ -0,0 +1,59 @@ +import React, { FC } from "react"; +import Image from "next/image"; + +import { Typography } from "@mui/material"; + +import { percentFormatter, usdFormatter } from "@mrgnlabs/mrgn-common"; +import { ExtendedBankInfo } from "@mrgnlabs/marginfi-v2-ui-state"; + +import { MrgnTooltip } from "~/components/common/MrgnTooltip"; + +export const AssetCardHeader: FC<{ + bank: ExtendedBankInfo; + isInLendingMode: boolean; + rateAP: string; +}> = ({ bank, isInLendingMode, rateAP }) => { + return ( +
+
+
+ {bank.meta.tokenLogoUri && ( + {bank.meta.tokenSymbol} + )} +
+
+
{bank.meta.tokenSymbol}
+
{usdFormatter.format(bank.info.state.price)}
+
+
+
+
+ {bank.meta.tokenSymbol === "UXD" && isInLendingMode && ( +
+ + + Liquidity rewards + + {`${percentFormatter.format(bank.info.state.lendingRate)} Supply APY + ${percentFormatter.format( + bank.info.state.emissionsRate + )} UXP rewards.`} +
+ + Learn more. + + + } + placement="left" + > + info +
+
+ )} +
+
{rateAP.concat(...[" ", isInLendingMode ? "APY" : "APR"])}
+
+
+ ); +}; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardPosition.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardPosition.tsx new file mode 100644 index 0000000000..653a6832cc --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardPosition.tsx @@ -0,0 +1,44 @@ +import React, { FC, useState } from "react"; + +import { usdFormatter } from "@mrgnlabs/mrgn-common"; +import { ActiveBankInfo } from "@mrgnlabs/marginfi-v2-ui-state"; + +import ExpandLessIcon from "@mui/icons-material/ExpandLess"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; + +export const AssetCardPosition: FC<{ + activeBank: ActiveBankInfo; +}> = ({ activeBank }) => { + const [isCollapsed, setIsCollapsed] = useState(true); + + return ( +
+
+
Your position details
+ setIsCollapsed(!isCollapsed)}> + {isCollapsed ? : } + +
+ {!isCollapsed && ( +
+
+
+ {(activeBank as ActiveBankInfo).position.isLending ? "Lending" : "Borrowing"} +
+
+ {(activeBank as ActiveBankInfo).position.amount.toFixed(activeBank.info.state.mintDecimals) + + " " + + activeBank.meta.tokenSymbol} +
+
+
+
USD value
+
+ {usdFormatter.format((activeBank as ActiveBankInfo).position.usdValue)} +
+
+
+ )} +
+ ); +}; diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx index 6fb1903b14..ddf9408254 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardStats.tsx @@ -1,22 +1,11 @@ -import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; +import React, { FC } from "react"; import Image from "next/image"; -import { TableCell, TableRow } from "@mui/material"; -import { styled } from "@mui/material/styles"; -import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; -import { useMrgnlendStore, useUserProfileStore } from "~/store"; -import Badge from "@mui/material/Badge"; -import { - WSOL_MINT, - groupedNumberFormatterDyn, - numeralFormatter, - percentFormatter, - uiToNative, - usdFormatter, -} from "@mrgnlabs/mrgn-common"; -import { ExtendedBankInfo, ActionType, getCurrentAction, ExtendedBankMetadata } from "@mrgnlabs/marginfi-v2-ui-state"; -import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2"; +import { numeralFormatter, percentFormatterDyn } from "@mrgnlabs/mrgn-common"; +import { ExtendedBankInfo } from "@mrgnlabs/marginfi-v2-ui-state"; + +import { MrgnTooltip } from "~/components/common/MrgnTooltip"; export const AssetCardStats: FC<{ bank: ExtendedBankInfo; @@ -37,30 +26,75 @@ export const AssetCardStats: FC<{ bankFilled, isInLendingMode, }) => { - console.log({ totalDepositsOrBorrows }); return ( -
-
-
Weight
-
{assetWeight}
+
+
+
+ {isInLendingMode ? "Weight" : "LTV"} +
+ + + {isInLendingMode ? "Weight" : "LTV"} + + + {isInLendingMode + ? "How much your assets count for collateral, relative to their USD value. The higher the weight, the more collateral you can borrow against it." + : "How much you can borrow against your free collateral. The higher the LTV, the more you can borrow against your free collateral."} + + + } + placement="top" + > + info + +
+
+
{assetWeight}
- {/* TODO: Add seperator */} -
-
{isInLendingMode ? "Deposits" : "Available"}
-
{numeralFormatter(totalDepositsOrBorrows)}
+ +
+
+ {isInLendingMode ? "Deposits" : "Available"} +
+ + + {isInLendingMode ? "Total deposits" : "Total available"} + + + {isInLendingMode + ? "Total marginfi deposits for each asset. Everything is denominated in native tokens." + : "The amount of tokens available to borrow for each asset. Calculated as the minimum of the asset's borrow limit and available liquidity that has not yet been borrowed."} + + + } + placement="top" + > + info + +
+
+
{numeralFormatter(totalDepositsOrBorrows)}
{isBankHigh && ( -
- {percentFormatter.format( +
+ {percentFormatterDyn.format( (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) / bankFilled - )} + ) + " FILLED"}
)}
- {/* TODO: Add seperator */} -
-
Your Balance
-
{userBalance + " " + bank.meta.tokenSymbol}
+ +
+
Your Balance
+
{userBalance + " " + bank.meta.tokenSymbol}
); }; + +function Separator() { + return
; +} diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx index 3528673ecf..980abbfcca 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx @@ -1,19 +1,18 @@ -import React, { FC, useEffect, useRef, useState } from "react"; +import React, { FC, useRef, useState } from "react"; import Image from "next/image"; -import { useHotkeys } from "react-hotkeys-hook"; -import { Card, Table, TableHead, TableBody, TableContainer, TableCell } from "@mui/material"; -import { styled } from "@mui/material/styles"; -import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; -import Typography from "@mui/material/Typography"; +import { Skeleton, Switch, Typography } from "@mui/material"; import { useMrgnlendStore, useUserProfileStore } from "~/store"; import { useWalletContext } from "~/hooks/useWalletContext"; -import { BorrowLendToggle } from "~/components/common/AssetList/BorrowLendToggle"; -import { AssetCard } from "./AssetCard"; +import { BorrowLendToggle } from "~/components/common/AssetList"; +import { MrgnTooltip } from "~/components/common/MrgnTooltip"; -// import { LoadingAsset, AssetRow } from "./AssetRow"; +import { AssetCard } from "./AssetCard"; export const MobileAssetsList: FC = () => { + const [isFiltered, setIsFiltered] = useState(false); + const togglePositions = () => setIsFiltered((previousState) => !previousState); + const { connected } = useWalletContext(); const [isStoreInitialized, sortedBanks, nativeSolBalance, selectedAccount] = useMrgnlendStore((state) => [ state.initialized, @@ -35,29 +34,78 @@ export const MobileAssetsList: FC = () => {
+
+ +
Filter my positions
+
+
+
Global pool
+
+ {sortedBanks + .filter((b) => !b.info.state.isIsolated) + .filter((b) => (isFiltered ? b.isActive : true)) + .map((bank, i) => + isStoreInitialized ? ( + + ) : ( + + ) + )} +
+
-
Global pool
- {sortedBanks - .filter((b) => !b.info.state.isIsolated) - .map((bank, i) => - isStoreInitialized ? ( - - ) : ( - // TODO add skeleton lib & component if green light - <> - ) - )} +
+ Isolated pool + + + Isolated pools are risky ⚠️ + + Assets in isolated pools cannot be used as collateral. When you borrow an isolated asset, you cannot + borrow other assets. Isolated pools should be considered particularly risky. As always, remember that + marginfi is a decentralized protocol and all deposited funds are at risk. + + } + placement="top" + > + info + +
+
+ {sortedBanks + .filter((b) => b.info.state.isIsolated) + .filter((b) => (isFiltered ? b.isActive : true)) + .map((bank, i) => + isStoreInitialized ? ( + + ) : ( + + ) + )} +
); diff --git a/apps/marginfi-v2-ui/src/pages/index.tsx b/apps/marginfi-v2-ui/src/pages/index.tsx index 759d99aea8..aafa32e979 100644 --- a/apps/marginfi-v2-ui/src/pages/index.tsx +++ b/apps/marginfi-v2-ui/src/pages/index.tsx @@ -100,7 +100,7 @@ const Home = () => { - LETS GOOOOO BIG +
diff --git a/apps/marginfi-v2-ui/tailwind.config.js b/apps/marginfi-v2-ui/tailwind.config.js index 944cc04293..3f0c40a196 100644 --- a/apps/marginfi-v2-ui/tailwind.config.js +++ b/apps/marginfi-v2-ui/tailwind.config.js @@ -29,7 +29,7 @@ module.exports = { "usd-equiv": "rgba(113, 119, 126, 0.3)", "btn-light": "rgb(227, 227, 227)", success: "#75ba80", - warning: "#daa204)", + warning: "#daa204", error: "#e07d6f", }, }, diff --git a/apps/marginfi-v2-ui/tsconfig.json b/apps/marginfi-v2-ui/tsconfig.json index 5f2861ee6c..5fe65688ee 100644 --- a/apps/marginfi-v2-ui/tsconfig.json +++ b/apps/marginfi-v2-ui/tsconfig.json @@ -2,6 +2,8 @@ "extends": "@mrgnlabs/tsconfig/nextjs.json", "compilerOptions": { "jsx": "preserve", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, "downlevelIteration": true, "paths": { "~/*": [ From ab9ce245dec2482cf192e649be2ed8a07310fe0a Mon Sep 17 00:00:00 2001 From: Kobe Leenders Date: Fri, 8 Sep 2023 21:08:03 +0200 Subject: [PATCH 005/351] fix(mfi-v2-ui): build fix --- .../MobileAssetsList/AssetCard/AssetCard.tsx | 2 +- .../AssetCard/AssetCardActions.tsx | 2 +- .../mobile/MobileAssetsList/MobileAssetsList.tsx | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx index 6798772788..3f9c98ec22 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx @@ -96,7 +96,7 @@ export const AssetCard: FC<{ ); return ( -
+
{ badgeContent={`${i + 1}`} /> ) : ( - + ) )}
@@ -102,7 +108,13 @@ export const MobileAssetsList: FC = () => { badgeContent={`${i + 1}`} /> ) : ( - + ) )}
From 03e1ac6548ca8dcd4f02fa7ecedaba4a6120a206 Mon Sep 17 00:00:00 2001 From: Kobe Leenders Date: Sat, 9 Sep 2023 13:17:29 +0200 Subject: [PATCH 006/351] fix(mfi-v2-ui): PR changes --- .../desktop/AssetsList/AssetRow/AssetRow.tsx | 10 +-- .../MobileAssetsList/AssetCard/AssetCard.tsx | 4 +- .../AssetCard/AssetCardStats.tsx | 6 +- .../MobileAssetsList/MobileAssetsList.tsx | 7 --- .../src/hooks/useAssetItemData.ts | 13 ++-- apps/marginfi-v2-ui/src/pages/index.tsx | 63 +++++++++++++------ .../src/components/Lend/PoolCard/PoolCard.tsx | 2 +- .../Lend/PoolCard/PoolCardStats.tsx | 12 ++-- 8 files changed, 65 insertions(+), 52 deletions(-) diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx index 13cc94b65d..a647593acf 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx @@ -47,7 +47,7 @@ const AssetRow: FC<{ const [lendZoomLevel, denominationUSD] = useUserProfileStore((state) => [state.lendZoomLevel, state.denominationUSD]); const setIsRefreshingStore = useMrgnlendStore((state) => state.setIsRefreshingStore); const [mfiClient, fetchMrgnlendState] = useMrgnlendStore((state) => [state.marginfiClient, state.fetchMrgnlendState]); - const { rateAP, assetWeight, isBankFilled, isBankHigh, bankFilled } = useAssetItemData({ bank, isInLendingMode }); + const { rateAP, assetWeight, isBankFilled, isBankHigh, bankCap } = useAssetItemData({ bank, isInLendingMode }); const assetPriceOffset = useMemo( () => @@ -253,7 +253,7 @@ const AssetRow: FC<{ {isBankHigh && (isBankFilled ? "Limit Reached" : "Approaching Limit")} {`${bank.meta.tokenSymbol} ${isInLendingMode ? "deposits" : "borrows"} are at ${percentFormatter.format( - (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) / bankFilled + (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) / bankCap )} capacity.`}
@@ -315,10 +315,10 @@ const AssetRow: FC<{ style={{ fontWeight: 300 }} > {denominationUSD - ? usdFormatter.format(bankFilled * bank.info.state.price) + ? usdFormatter.format(bankCap * bank.info.state.price) : lendZoomLevel < 2 - ? groupedNumberFormatterDyn.format(bankFilled) - : numeralFormatter(bankFilled)} + ? groupedNumberFormatterDyn.format(bankCap) + : numeralFormatter(bankCap)} )} diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx index 3f9c98ec22..1c9640b099 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx @@ -35,7 +35,7 @@ export const AssetCard: FC<{ showHotkeyBadges, badgeContent, }) => { - const { rateAP, assetWeight, isBankFilled, isBankHigh, bankFilled } = useAssetItemData({ bank, isInLendingMode }); + const { rateAP, assetWeight, isBankFilled, isBankHigh, bankCap } = useAssetItemData({ bank, isInLendingMode }); const [mfiClient, fetchMrgnlendState] = useMrgnlendStore((state) => [state.marginfiClient, state.fetchMrgnlendState]); const setIsRefreshingStore = useMrgnlendStore((state) => state.setIsRefreshingStore); const { connected } = useWalletContext(); @@ -106,7 +106,7 @@ export const AssetCard: FC<{ isInLendingMode={isInLendingMode} isBankFilled={isBankFilled} isBankHigh={isBankHigh} - bankFilled={bankFilled} + bankCap={bankCap} /> {bank.isActive && } = ({ bank, @@ -23,7 +23,7 @@ export const AssetCardStats: FC<{ userBalance, isBankFilled, isBankHigh, - bankFilled, + bankCap, isInLendingMode, }) => { return ( @@ -81,7 +81,7 @@ export const AssetCardStats: FC<{ {isBankHigh && (
{percentFormatterDyn.format( - (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) / bankFilled + (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) / bankCap ) + " FILLED"}
)} diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx index 9eed63cc6e..40a7b35cd9 100644 --- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx @@ -27,7 +27,6 @@ export const MobileAssetsList: FC = () => { ]); const inputRefs = useRef>({}); const [isInLendingMode, setIsInLendingMode] = useState(true); - const [isHotkeyMode, setIsHotkeyMode] = useState(false); return ( <> @@ -54,9 +53,6 @@ export const MobileAssetsList: FC = () => { isConnected={connected} marginfiAccount={selectedAccount} inputRefs={inputRefs} - hasHotkey={true} - showHotkeyBadges={showBadges} - badgeContent={`${i + 1}`} /> ) : ( { isConnected={connected} marginfiAccount={selectedAccount} inputRefs={inputRefs} - hasHotkey={true} - showHotkeyBadges={showBadges} - badgeContent={`${i + 1}`} /> ) : ( (isInLendingMode ? bank.info.rawBank.config.depositLimit : bank.info.rawBank.config.borrowLimit), [isInLendingMode, bank.info.rawBank.config] ); const isBankFilled = useMemo( - () => (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) >= bankFilled * 0.99999, - [bankFilled, isInLendingMode, bank.info.state] + () => (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) >= bankCap * 0.99999, + [bankCap, isInLendingMode, bank.info.state] ); const isBankHigh = useMemo( - () => (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) >= bankFilled * 0.9, - [bankFilled, isInLendingMode, bank.info.state] + () => (isInLendingMode ? bank.info.state.totalDeposits : bank.info.state.totalBorrows) >= bankCap * 0.9, + [bankCap, isInLendingMode, bank.info.state] ); - return { rateAP, assetWeight, bankFilled, isBankFilled, isBankHigh }; + return { rateAP, assetWeight, bankCap, isBankFilled, isBankHigh }; } diff --git a/apps/marginfi-v2-ui/src/pages/index.tsx b/apps/marginfi-v2-ui/src/pages/index.tsx index aafa32e979..e67f71d5b3 100644 --- a/apps/marginfi-v2-ui/src/pages/index.tsx +++ b/apps/marginfi-v2-ui/src/pages/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { FC, useEffect } from "react"; import { Banner } from "~/components/desktop/Banner"; import { PageHeader } from "~/components/desktop/PageHeader"; import { useWalletContext } from "~/hooks/useWalletContext"; @@ -10,26 +10,49 @@ import { OverlaySpinner } from "~/components/desktop/OverlaySpinner"; import { useConnection } from "@solana/wallet-adapter-react"; import { Desktop, Mobile } from "~/mediaQueries"; -const DesktopAccountSummary = dynamic( - async () => (await import("~/components/desktop/DesktopAccountSummary")).DesktopAccountSummary, - { - ssr: false, - } -); -const MobileAccountSummary = dynamic( - async () => (await import("~/components/mobile/MobileAccountSummary")).MobileAccountSummary, - { +const DesktopAccountSummary = () => { + const DesktopAccountSummary = dynamic( + async () => (await import("~/components/desktop/DesktopAccountSummary")).DesktopAccountSummary, + { + ssr: false, + } + ); + + return ; +}; + +const AssetsList = () => { + const AssetsList = dynamic(async () => (await import("~/components/desktop/AssetsList")).AssetsList, { ssr: false }); + return ; +}; + +const UserPositions = () => { + const UserPositions = dynamic(async () => (await import("~/components/desktop/UserPositions")).UserPositions, { ssr: false, - } -); -const AssetsList = dynamic(async () => (await import("~/components/desktop/AssetsList")).AssetsList, { ssr: false }); -const MobileAssetsList = dynamic(async () => (await import("~/components/mobile/MobileAssetsList")).MobileAssetsList, { - ssr: false, -}); + }); -const UserPositions = dynamic(async () => (await import("~/components/desktop/UserPositions")).UserPositions, { - ssr: false, -}); + return ; +}; + +const MobileAccountSummary = () => { + const MobileAccountSummary = dynamic( + async () => (await import("~/components/mobile/MobileAccountSummary")).MobileAccountSummary, + { + ssr: false, + } + ); + return ; +}; + +const MobileAssetsList = () => { + const MobileAssetsList = dynamic( + async () => (await import("~/components/mobile/MobileAssetsList")).MobileAssetsList, + { + ssr: false, + } + ); + return ; +}; const Home = () => { const { walletAddress, wallet, isOverride } = useWalletContext(); @@ -89,7 +112,6 @@ const Home = () => { {walletAddress && marginfiAccountCount > 1 && ( )} -
@@ -105,6 +127,7 @@ const Home = () => {
+
); diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx index 69b6e95bfc..0ad2694268 100644 --- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx +++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx @@ -154,7 +154,7 @@ export function PoolCard({ diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardStats.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardStats.tsx index 619564097e..860116b337 100644 --- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardStats.tsx +++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardStats.tsx @@ -10,10 +10,10 @@ type Props = { bank: ExtendedBankInfo; nativeSolBalance: number; isInLendingMode: boolean; - bankFilled: number; + bankCap: number; }; -export function PoolCardStats({ bank, isInLendingMode, nativeSolBalance, bankFilled }: Props) { +export function PoolCardStats({ bank, isInLendingMode, nativeSolBalance, bankCap }: Props) { const assetWeight = useMemo(() => { if (bank.info.rawBank.config.assetWeightInit.toNumber() <= 0) { return "-"; @@ -43,9 +43,9 @@ export function PoolCardStats({ bank, isInLendingMode, nativeSolBalance, bankFil [bank, nativeSolBalance] ); - const isFilled = useMemo(() => bankFilled >= 0.9999, [bankFilled]); + const isFilled = useMemo(() => bankCap >= 0.9999, [bankCap]); - const isHigh = useMemo(() => bankFilled >= 0.9, [bankFilled]); + const isHigh = useMemo(() => bankCap >= 0.9, [bankCap]); return ( @@ -57,9 +57,7 @@ export function PoolCardStats({ bank, isInLendingMode, nativeSolBalance, bankFil {isInLendingMode ? "Deposits" : "Available"} {bankAmount} - {isHigh && ( - {percentFormatter.format(bankFilled)} - )} + {isHigh && {percentFormatter.format(bankCap)}} From 4954cc145cbad1ce3c8c7f8d34fd6d1c229cd959 Mon Sep 17 00:00:00 2001 From: Kobe Leenders Date: Sat, 9 Sep 2023 15:20:40 +0200 Subject: [PATCH 007/351] feat(mfi-v2-xnft): added icons & cleanup feature --- apps/marginfi-v2-xnft/App.tsx | 7 +- .../src/assets/icons/PieChartIcon.tsx | 16 ++++ .../src/assets/icons/ReceiveMoneyIcon.tsx | 19 ++++ .../src/assets/icons/TokenSwapIcon.tsx | 16 ++++ .../src/assets/icons/chevron-down.svg | 3 - .../src/assets/icons/index.ts | 3 + .../src/components/Lend/PoolCard/PoolCard.tsx | 46 +++++++++- .../Lend/PoolCard/PoolCardActions.tsx | 31 +++---- .../Lend/PoolCard/PoolCardSkeleton.tsx | 2 +- .../Lend/PoolCard/PoolCardStats.tsx | 2 +- .../src/screens/LendScreen.tsx | 88 ++++++++++--------- 11 files changed, 165 insertions(+), 68 deletions(-) create mode 100644 apps/marginfi-v2-xnft/src/assets/icons/PieChartIcon.tsx create mode 100644 apps/marginfi-v2-xnft/src/assets/icons/ReceiveMoneyIcon.tsx create mode 100644 apps/marginfi-v2-xnft/src/assets/icons/TokenSwapIcon.tsx delete mode 100644 apps/marginfi-v2-xnft/src/assets/icons/chevron-down.svg diff --git a/apps/marginfi-v2-xnft/App.tsx b/apps/marginfi-v2-xnft/App.tsx index 8b3921580b..d0f0da9d87 100644 --- a/apps/marginfi-v2-xnft/App.tsx +++ b/apps/marginfi-v2-xnft/App.tsx @@ -16,6 +16,7 @@ import { SwapContextProvider } from "~/context"; import { useConnection } from "~/hooks/useConnection"; import { useWallet } from "~/hooks/useWallet"; import { ROUTE_CACHE_DURATION } from "~/consts"; +import { PieChartIcon, ReceiveMoneyIcon, TokenSwapIcon } from "~/assets/icons"; require("~/styles/globals.css"); require("~/styles/fonts.css"); @@ -82,7 +83,7 @@ function TabNavigator() { options={{ header: (props: BottomTabHeaderProps) => , tabBarLabel: "Lend", - tabBarIcon: ({ color, size }) => , + tabBarIcon: ({ color, size }) => , }} /> , tabBarLabel: "Swap", - tabBarIcon: ({ color, size }) => , + tabBarIcon: ({ color, size }) => , }} /> , tabBarLabel: "Portfolio", - tabBarIcon: ({ color, size }) => , + tabBarIcon: ({ color, size }) => , }} /> diff --git a/apps/marginfi-v2-xnft/src/assets/icons/PieChartIcon.tsx b/apps/marginfi-v2-xnft/src/assets/icons/PieChartIcon.tsx new file mode 100644 index 0000000000..7d3c16a0e3 --- /dev/null +++ b/apps/marginfi-v2-xnft/src/assets/icons/PieChartIcon.tsx @@ -0,0 +1,16 @@ +import React from "react"; + +interface PieChartIconProps extends React.SVGAttributes { + color?: string; +} + +export const PieChartIcon: React.FC = ({ width = "24", height = "24", color = "white" }) => { + return ( + + + + ); +}; diff --git a/apps/marginfi-v2-xnft/src/assets/icons/ReceiveMoneyIcon.tsx b/apps/marginfi-v2-xnft/src/assets/icons/ReceiveMoneyIcon.tsx new file mode 100644 index 0000000000..763a18e82a --- /dev/null +++ b/apps/marginfi-v2-xnft/src/assets/icons/ReceiveMoneyIcon.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +interface ReceiveMoneyIconProps extends React.SVGAttributes { + color?: string; +} + +export const ReceiveMoneyIcon: React.FC = ({ width = "24", height = "24", color = "black" }) => { + return ( + + + + + + ); +}; diff --git a/apps/marginfi-v2-xnft/src/assets/icons/TokenSwapIcon.tsx b/apps/marginfi-v2-xnft/src/assets/icons/TokenSwapIcon.tsx new file mode 100644 index 0000000000..c83464147a --- /dev/null +++ b/apps/marginfi-v2-xnft/src/assets/icons/TokenSwapIcon.tsx @@ -0,0 +1,16 @@ +import React from "react"; + +interface TokenSwapIconProps extends React.SVGAttributes { + color?: string; +} + +export const TokenSwapIcon: React.FC = ({ width = "24", height = "24", color = "black" }) => { + return ( + + + + ); +}; diff --git a/apps/marginfi-v2-xnft/src/assets/icons/chevron-down.svg b/apps/marginfi-v2-xnft/src/assets/icons/chevron-down.svg deleted file mode 100644 index 1b95cdaf65..0000000000 --- a/apps/marginfi-v2-xnft/src/assets/icons/chevron-down.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/apps/marginfi-v2-xnft/src/assets/icons/index.ts b/apps/marginfi-v2-xnft/src/assets/icons/index.ts index 36e9e1618e..abd3687121 100644 --- a/apps/marginfi-v2-xnft/src/assets/icons/index.ts +++ b/apps/marginfi-v2-xnft/src/assets/icons/index.ts @@ -11,3 +11,6 @@ export * from "./RefreshIcon"; export * from "./SettingsIcon"; export * from "./CloseIcon"; export * from "./ErrorIcon"; +export * from "./PieChartIcon"; +export * from "./ReceiveMoneyIcon"; +export * from "./TokenSwapIcon"; diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx index 69b6e95bfc..88a72cff52 100644 --- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx +++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx @@ -7,7 +7,7 @@ import { MarginfiAccountWrapper, MarginfiClient } from "@mrgnlabs/marginfi-clien import { PoolCardPosition } from "./PoolCardPosition"; import { useConnection } from "~/hooks/useConnection"; import { ActionType, Emissions, ExtendedBankInfo, FEE_MARGIN, getCurrentAction } from "@mrgnlabs/marginfi-v2-ui-state"; -import { showErrorToast } from "~/utils"; +import { showErrorToast, showSuccessToast } from "~/utils"; import { percentFormatter, usdFormatter } from "@mrgnlabs/mrgn-common"; type Props = { @@ -120,6 +120,8 @@ export function PoolCard({ const withdrawAll = bankInfo.isActive ? borrowOrLendAmount === bankInfo.position.amount : false; await _marginfiAccount.withdraw(borrowOrLendAmount, bankInfo.address, withdrawAll); } + + showSuccessToast(`${currentAction + "ing"} ${borrowOrLendAmount} ${bankInfo.meta.tokenSymbol} 👍`); } catch (error: any) { console.log(`Error while ${currentAction + "ing"}`); console.log(error); @@ -136,8 +138,46 @@ export function PoolCard({ [bankInfo, connection, currentAction, marginfiAccount, marginfiClient, nativeSolBalance, reloadBanks] ); + const closeBalance = useCallback(async () => { + if (!marginfiAccount) { + showErrorToast("marginfi account not ready."); + return; + } + + if (!bankInfo.isActive) { + showErrorToast("no position to close."); + return; + } + + try { + if (bankInfo.position.isLending) { + await marginfiAccount.withdraw(0, bankInfo.address, true); + } else { + await marginfiAccount.repay(0, bankInfo.address, true); + } + showSuccessToast("Closing 👍"); + } catch (error: any) { + showSuccessToast(`Error while closing balance: ${error.message}`); + console.log(`Error while closing balance`); + console.log(error); + } + + // TODO: set values back to 0 + try { + await reloadBanks(); + } catch (error: any) { + console.log("Error while reloading state"); + console.log(error); + } + }, [bankInfo, marginfiAccount, reloadBanks]); + return ( - + {bankInfo.meta.tokenSymbol} @@ -163,7 +203,7 @@ export function PoolCard({ currentAction={currentAction} isBankFilled={isInLendingMode ? depositFilled >= 0.9999 : borrowFilled >= 0.9999} bank={bankInfo} - onAction={(amount) => borrowOrLend(amount)} + onAction={(amount) => (amount ? borrowOrLend(amount) : closeBalance())} /> ); diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardActions.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardActions.tsx index 4546412ead..d2671d033f 100644 --- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardActions.tsx +++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardActions.tsx @@ -3,12 +3,13 @@ import { View, Text, Pressable } from "react-native"; import tw from "~/styles/tailwind"; import { NumberInput, PrimaryButton, SecondaryButton } from "~/components/Common"; import { ActionType, ExtendedBankInfo } from "@mrgnlabs/marginfi-v2-ui-state"; +import { uiToNative } from "@mrgnlabs/mrgn-common"; type Props = { currentAction: ActionType; bank: ExtendedBankInfo; isBankFilled: boolean; - onAction: (amount: string) => void; + onAction: (amount?: string) => void; }; export function PoolCardActions({ currentAction, bank, isBankFilled, onAction }: Props) { @@ -27,20 +28,20 @@ export function PoolCardActions({ currentAction, bank, isBankFilled, onAction }: } }, [bank.userInfo, currentAction]); - const isDisabled = useMemo(() => { - switch (currentAction) { - case ActionType.Deposit: - return isBankFilled; - case ActionType.Withdraw: - return false; - case ActionType.Borrow: - return isBankFilled; - case ActionType.Repay: - return false; - } - }, [currentAction, isBankFilled]); + const isDust = useMemo( + () => bank.isActive && uiToNative(bank.position.amount, bank.info.state.mintDecimals).isZero(), + [bank] + ); + + const isDisabled = useMemo( + () => + (isDust && uiToNative(bank.userInfo.tokenAccount.balance, bank.info.state.mintDecimals).isZero()) || + maxAmount === 0, + [currentAction, bank, isDust, maxAmount] + ); const buttonText = useMemo(() => { + if (isDust) return "Close"; switch (currentAction) { case ActionType.Deposit: return isDisabled ? "Deposits reached the limit" : "Supply"; @@ -51,7 +52,7 @@ export function PoolCardActions({ currentAction, bank, isBankFilled, onAction }: case ActionType.Repay: return "Repay"; } - }, [currentAction, isDisabled]); + }, [currentAction, isDisabled, isDust]); return ( <> @@ -72,7 +73,7 @@ export function PoolCardActions({ currentAction, bank, isBankFilled, onAction }: {currentAction == ActionType.Withdraw || currentAction == ActionType.Repay ? ( - onAction(amount)} /> + (isDust ? onAction() : onAction(amount))} /> ) : ( onAction(amount)} /> )} diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardSkeleton.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardSkeleton.tsx index ca9d8e9a53..cae35f07d7 100644 --- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardSkeleton.tsx +++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardSkeleton.tsx @@ -4,7 +4,7 @@ import { View } from "react-native"; import tw from "~/styles/tailwind"; export const PoolCardSkeleton = (props?: JSX.IntrinsicAttributes & IContentLoaderProps) => ( - + bankFilled >= 0.9, [bankFilled]); return ( - + Weight {assetWeight} diff --git a/apps/marginfi-v2-xnft/src/screens/LendScreen.tsx b/apps/marginfi-v2-xnft/src/screens/LendScreen.tsx index 7b95940b21..e1b967efd1 100644 --- a/apps/marginfi-v2-xnft/src/screens/LendScreen.tsx +++ b/apps/marginfi-v2-xnft/src/screens/LendScreen.tsx @@ -68,52 +68,56 @@ export function LendScreen() { Filter my positions Global pools - {extendedBankInfos.length > 0 ? ( - globalPools.length > 0 ? ( - globalPools.map((extendedBankInfo, idx) => ( - { - if (!connection) return; - fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet }); - }} - marginfiClient={marginfiClient} - > - )) + {/* + {extendedBankInfos.length > 0 ? ( + globalPools.length > 0 ? ( + globalPools.map((extendedBankInfo, idx) => ( + { + if (!connection) return; + fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet }); + }} + marginfiClient={marginfiClient} + > + )) + ) : ( + No Global Pools Found + ) ) : ( - No Global Pools Found - ) - ) : ( - - )} + + )} + */} Isolated pools - {extendedBankInfos.length > 0 ? ( - isolatedPools.length > 0 ? ( - isolatedPools.map((extendedBankInfo, idx) => ( - { - if (!connection) return; - fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet }); - }} - marginfiClient={marginfiClient} - > - )) + {/* + {extendedBankInfos.length > 0 ? ( + isolatedPools.length > 0 ? ( + isolatedPools.map((extendedBankInfo, idx) => ( + { + if (!connection) return; + fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet }); + }} + marginfiClient={marginfiClient} + > + )) + ) : ( + No Isolated Pools Found + ) ) : ( - No Isolated Pools Found - ) - ) : ( - - )} + + )} + */} From e6dd784f3f9075114edbf68e81efe5f4afdf3227 Mon Sep 17 00:00:00 2001 From: Kobe Leenders Date: Sat, 9 Sep 2023 16:32:41 +0200 Subject: [PATCH 008/351] feat(mfi-v2-ui): added navbar --- apps/marginfi-v2-ui/public/pie_chart.svg | 1 + apps/marginfi-v2-ui/public/receive_money.svg | 1 + apps/marginfi-v2-ui/public/token_swap.svg | 1 + .../Navbar}/WalletButton.tsx | 0 .../src/components/common/Navbar/index.ts | 1 + .../desktop/DesktopNavbar/DesktopNavbar.tsx | 2 +- .../mobile/DesktopNavbar/MobileNavbar.tsx | 76 ------------------- .../mobile/DesktopNavbar/WalletButton.tsx | 22 ------ .../AirdropZone.module.css | 0 .../AirdropZone.tsx | 0 .../MobileNavbar.module.css | 0 .../mobile/MobileNavbar/MobileNavbar.tsx | 69 +++++++++++++++++ .../{DesktopNavbar => MobileNavbar}/index.tsx | 0 apps/marginfi-v2-ui/src/pages/_app.tsx | 26 ++++--- apps/marginfi-v2-ui/src/pages/points.tsx | 2 +- 15 files changed, 92 insertions(+), 109 deletions(-) create mode 100644 apps/marginfi-v2-ui/public/pie_chart.svg create mode 100644 apps/marginfi-v2-ui/public/receive_money.svg create mode 100644 apps/marginfi-v2-ui/public/token_swap.svg rename apps/marginfi-v2-ui/src/components/{desktop/DesktopNavbar => common/Navbar}/WalletButton.tsx (100%) create mode 100644 apps/marginfi-v2-ui/src/components/common/Navbar/index.ts delete mode 100644 apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx delete mode 100644 apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx rename apps/marginfi-v2-ui/src/components/mobile/{DesktopNavbar => MobileNavbar}/AirdropZone.module.css (100%) rename apps/marginfi-v2-ui/src/components/mobile/{DesktopNavbar => MobileNavbar}/AirdropZone.tsx (100%) rename apps/marginfi-v2-ui/src/components/mobile/{DesktopNavbar => MobileNavbar}/MobileNavbar.module.css (100%) create mode 100644 apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/MobileNavbar.tsx rename apps/marginfi-v2-ui/src/components/mobile/{DesktopNavbar => MobileNavbar}/index.tsx (100%) diff --git a/apps/marginfi-v2-ui/public/pie_chart.svg b/apps/marginfi-v2-ui/public/pie_chart.svg new file mode 100644 index 0000000000..8027ee53c6 --- /dev/null +++ b/apps/marginfi-v2-ui/public/pie_chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/marginfi-v2-ui/public/receive_money.svg b/apps/marginfi-v2-ui/public/receive_money.svg new file mode 100644 index 0000000000..e660a612fa --- /dev/null +++ b/apps/marginfi-v2-ui/public/receive_money.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/marginfi-v2-ui/public/token_swap.svg b/apps/marginfi-v2-ui/public/token_swap.svg new file mode 100644 index 0000000000..fc195a0ccd --- /dev/null +++ b/apps/marginfi-v2-ui/public/token_swap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx b/apps/marginfi-v2-ui/src/components/common/Navbar/WalletButton.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/WalletButton.tsx rename to apps/marginfi-v2-ui/src/components/common/Navbar/WalletButton.tsx diff --git a/apps/marginfi-v2-ui/src/components/common/Navbar/index.ts b/apps/marginfi-v2-ui/src/components/common/Navbar/index.ts new file mode 100644 index 0000000000..778aed6c06 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/common/Navbar/index.ts @@ -0,0 +1 @@ +export * from "./WalletButton"; diff --git a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx index c5da39f773..b8439d7f0b 100644 --- a/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx +++ b/apps/marginfi-v2-ui/src/components/desktop/DesktopNavbar/DesktopNavbar.tsx @@ -2,7 +2,7 @@ import { FC, useEffect, useState } from "react"; import Link from "next/link"; import Image from "next/image"; import AirdropZone from "./AirdropZone"; -import { WalletButton } from "./WalletButton"; +import { WalletButton } from "~/components/common/Navbar"; import { useHotkeys } from "react-hotkeys-hook"; import { useMrgnlendStore, useUserProfileStore } from "~/store"; diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx deleted file mode 100644 index 947e008c87..0000000000 --- a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { FC, useEffect } from "react"; -import Link from "next/link"; -import Image from "next/image"; -import AirdropZone from "./AirdropZone"; -import { useUserProfileStore } from "~/store"; -import { useRouter } from "next/router"; -import { useFirebaseAccount } from "~/hooks/useFirebaseAccount"; -import { useWalletContext } from "~/hooks/useWalletContext"; - -// @todo implement second pretty navbar row -const MobileNavbar: FC = () => { - useFirebaseAccount(); - - const { connected, walletAddress } = useWalletContext(); - const router = useRouter(); - const [fetchPoints] = useUserProfileStore((state) => [state.fetchPoints]); - - useEffect(() => { - if (!walletAddress) return; - fetchPoints(walletAddress.toBase58()).catch(console.error); - }, [fetchPoints, walletAddress]); - - return ( -
- -
- ); -}; - -export { MobileNavbar }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx b/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx deleted file mode 100644 index e0811cd095..0000000000 --- a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/WalletButton.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import dynamic from "next/dynamic"; -import { FC } from "react"; -import { useWalletContext } from "~/hooks/useWalletContext"; - -const WalletMultiButtonDynamic = dynamic( - async () => (await import("@solana/wallet-adapter-react-ui")).WalletMultiButton, - { ssr: false } -); - -const WalletButton: FC = () => { - const { connected } = useWalletContext(); - - return ( -
- - {!connected &&
CONNECT
} -
-
- ); -}; - -export { WalletButton }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.module.css b/apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/AirdropZone.module.css similarity index 100% rename from apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.module.css rename to apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/AirdropZone.module.css diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/AirdropZone.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/AirdropZone.tsx rename to apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/AirdropZone.tsx diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.module.css b/apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/MobileNavbar.module.css similarity index 100% rename from apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/MobileNavbar.module.css rename to apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/MobileNavbar.module.css diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/MobileNavbar.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/MobileNavbar.tsx new file mode 100644 index 0000000000..f2b3d9da95 --- /dev/null +++ b/apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/MobileNavbar.tsx @@ -0,0 +1,69 @@ +import { FC, useEffect } from "react"; +import Link from "next/link"; +import Image from "next/image"; +import AirdropZone from "./AirdropZone"; +import { useUserProfileStore } from "~/store"; +import { useRouter } from "next/router"; +import { useFirebaseAccount } from "~/hooks/useFirebaseAccount"; +import { useWalletContext } from "~/hooks/useWalletContext"; + +// @todo implement second pretty navbar row +const MobileNavbar: FC = () => { + useFirebaseAccount(); + + const { connected, walletAddress } = useWalletContext(); + const router = useRouter(); + const [fetchPoints] = useUserProfileStore((state) => [state.fetchPoints]); + + useEffect(() => { + if (!walletAddress) return; + fetchPoints(walletAddress.toBase58()).catch(console.error); + }, [fetchPoints, walletAddress]); + + return ( +
+ +
+ ); +}; + +export { MobileNavbar }; diff --git a/apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/index.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/index.tsx similarity index 100% rename from apps/marginfi-v2-ui/src/components/mobile/DesktopNavbar/index.tsx rename to apps/marginfi-v2-ui/src/components/mobile/MobileNavbar/index.tsx diff --git a/apps/marginfi-v2-ui/src/pages/_app.tsx b/apps/marginfi-v2-ui/src/pages/_app.tsx index ac0fcccf6f..30be73c899 100644 --- a/apps/marginfi-v2-ui/src/pages/_app.tsx +++ b/apps/marginfi-v2-ui/src/pages/_app.tsx @@ -18,9 +18,9 @@ import "react-toastify/dist/ReactToastify.min.css"; import { ToastContainer } from "react-toastify"; import { Analytics } from "@vercel/analytics/react"; import dynamic from "next/dynamic"; -import { Desk } from "@mui/icons-material"; import { Desktop, Mobile } from "~/mediaQueries"; -import { MobileNavbar } from "~/components/mobile/DesktopNavbar"; +import { MobileNavbar } from "~/components/mobile/MobileNavbar"; +import { WalletButton } from "~/components/common/Navbar"; // Use require instead of import since order matters require("@solana/wallet-adapter-react-ui/styles.css"); @@ -28,7 +28,9 @@ require("~/styles/globals.css"); require("~/styles/fonts.css"); require("~/styles/asset-borders.css"); -const DesktopNavbar = dynamic(async () => (await import("~/components/desktop/DesktopNavbar")).DesktopNavbar, { ssr: false }); +const DesktopNavbar = dynamic(async () => (await import("~/components/desktop/DesktopNavbar")).DesktopNavbar, { + ssr: false, +}); const Footer = dynamic(async () => (await import("~/components/desktop/Footer")).Footer, { ssr: false }); // Matomo @@ -68,16 +70,22 @@ const MyApp = ({ Component, pageProps }: AppProps) => { +
+ + +
+