From 8a39441cd213aae704c47aa42eae784b4a0d73a9 Mon Sep 17 00:00:00 2001 From: Jeremy <168515712+jeremy-babylonlabs@users.noreply.github.com> Date: Sun, 1 Dec 2024 18:04:02 +1100 Subject: [PATCH] add block phase 1 banner and modal (#379) * add block phase 1 banner and modal * update the workding for the unbonding button * chore: make the network name dynamic based on btc network --------- Co-authored-by: wjrjerome --- .env.example | 3 +- .github/workflows/publish.yaml | 1 + Dockerfile | 3 + README.md | 1 + src/app/assets/banner-warning.svg | 3 + src/app/components/Delegations/Delegation.tsx | 33 ++++++++--- .../Modals/UnbondingDisabledModal.tsx | 59 +++++++++++++++++++ .../UnbondingDisabledBanner.tsx | 36 +++++++++++ src/app/page.tsx | 5 ++ src/config/index.ts | 6 ++ 10 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 src/app/assets/banner-warning.svg create mode 100644 src/app/components/Modals/UnbondingDisabledModal.tsx create mode 100644 src/app/components/UnbondingDisabledBanner/UnbondingDisabledBanner.tsx diff --git a/.env.example b/.env.example index d08db61f..5134925e 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,5 @@ NEXT_PUBLIC_MEMPOOL_API=https://mempool.space NEXT_PUBLIC_API_URL=https://staking-api.testnet.babylonchain.io NEXT_PUBLIC_POINTS_API_URL=https://points.testnet.babylonchain.io NEXT_PUBLIC_NETWORK=signet -NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=true \ No newline at end of file +NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=true +NEXT_PUBLIC_DISABLE_UNBONDING=false \ No newline at end of file diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 945fd2a9..0e6d228a 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -40,6 +40,7 @@ jobs: NEXT_PUBLIC_POINTS_API_URL=${{ vars.NEXT_PUBLIC_POINTS_API_URL }} NEXT_PUBLIC_NETWORK=${{ vars.NEXT_PUBLIC_NETWORK }} NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=${{ vars.NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES }} + NEXT_PUBLIC_DISABLE_UNBONDING=${{ vars.NEXT_PUBLIC_DISABLE_UNBONDING }} - name: Upload Docker image to workspace uses: actions/upload-artifact@v4 diff --git a/Dockerfile b/Dockerfile index e9b5ed96..c1ad4408 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,6 +29,9 @@ ENV NEXT_PUBLIC_NETWORK=${NEXT_PUBLIC_NETWORK} ARG NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES ENV NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=${NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES} +ARG NEXT_PUBLIC_DISABLE_UNBONDING +ENV NEXT_PUBLIC_DISABLE_UNBONDING=${NEXT_PUBLIC_DISABLE_UNBONDING} + RUN npm run build # Step 2. Production image, copy all the files and run next diff --git a/README.md b/README.md index 9b97fce3..e974cffc 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ where, - `NEXT_PUBLIC_NETWORK` specifies the BTC network environment - `NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES` boolean value to indicate whether display testing network related message. Default to true +- `NEXT_PUBLIC_DISABLE_UNBONDING` boolean value to indicate whether disable unbonding. Default to false Then, to start a development server: diff --git a/src/app/assets/banner-warning.svg b/src/app/assets/banner-warning.svg new file mode 100644 index 00000000..c2a2f346 --- /dev/null +++ b/src/app/assets/banner-warning.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/components/Delegations/Delegation.tsx b/src/app/components/Delegations/Delegation.tsx index 05e7fb81..ae0c93cb 100644 --- a/src/app/components/Delegations/Delegation.tsx +++ b/src/app/components/Delegations/Delegation.tsx @@ -7,7 +7,7 @@ import { Tooltip } from "react-tooltip"; import { useHealthCheck } from "@/app/hooks/useHealthCheck"; import { DelegationState, StakingTx } from "@/app/types/delegations"; import { GlobalParamsVersion } from "@/app/types/globalParams"; -import { shouldDisplayPoints } from "@/config"; +import { shouldDisableUnbonding, shouldDisplayPoints } from "@/config"; import { getNetworkConfig } from "@/config/network.config"; import { satoshiToBtc } from "@/utils/btcConversions"; import { durationTillNow } from "@/utils/formatTime"; @@ -65,15 +65,32 @@ export const Delegation: React.FC = ({ if (state === DelegationState.ACTIVE) { return (
- + +
+ ); } else if (state === DelegationState.UNBONDED) { diff --git a/src/app/components/Modals/UnbondingDisabledModal.tsx b/src/app/components/Modals/UnbondingDisabledModal.tsx new file mode 100644 index 00000000..afd98ba2 --- /dev/null +++ b/src/app/components/Modals/UnbondingDisabledModal.tsx @@ -0,0 +1,59 @@ +import { useState } from "react"; +import { IoMdClose } from "react-icons/io"; +import { useLocalStorage } from "usehooks-ts"; + +import { shouldDisableUnbonding } from "@/config"; +import { getNetworkConfig } from "@/config/network.config"; + +import { GeneralModal } from "./GeneralModal"; + +const Title: React.FC = () => { + return ( +

Unbonding disabled during Phase-2 Transition

+ ); +}; + +const Content: React.FC = () => { + const { network, coinName } = getNetworkConfig(); + + return ( +
+
+

+ In preparation for the upcoming Phase-2 {network} launch, on-demand + stake unbonding is disabled. +
+ Once the Phase-2 {network} is launched, you will be able to transit + your + {coinName} stake to Phase-2 and then unbond. +

+
+
+ ); +}; + +export const UnbondingDisabledModal: React.FC = () => { + const [unbondingDisabledModalOpened, setUnbondingDisabledModalOpened] = + useLocalStorage("bbn-unbonding-disabled-modal-opened", false); + + const [unbondingDisabledModalOpen, setUnbondingDisabledModalOpen] = useState( + !unbondingDisabledModalOpened && shouldDisableUnbonding(), + ); + + const onClose = () => { + setUnbondingDisabledModalOpen(false); + setUnbondingDisabledModalOpened(true); + }; + + return ( + +
+ + <button className="btn btn-circle btn-ghost btn-sm" onClick={onClose}> + <IoMdClose size={24} /> + </button> + </div> + <Content /> + </GeneralModal> + ); +}; diff --git a/src/app/components/UnbondingDisabledBanner/UnbondingDisabledBanner.tsx b/src/app/components/UnbondingDisabledBanner/UnbondingDisabledBanner.tsx new file mode 100644 index 00000000..f04dcfba --- /dev/null +++ b/src/app/components/UnbondingDisabledBanner/UnbondingDisabledBanner.tsx @@ -0,0 +1,36 @@ +import Image from "next/image"; +import { FC } from "react"; + +import BannerWarningIcon from "@/app/assets/banner-warning.svg"; +import { shouldDisableUnbonding } from "@/config"; +import { getNetworkConfig } from "@/config/network.config"; + +interface UnbondingDisabledBannerProps {} + +export const UnbondingDisabledBanner: FC<UnbondingDisabledBannerProps> = () => { + if (!shouldDisableUnbonding()) return null; + const { network, coinName } = getNetworkConfig(); + + return ( + <div className="w-full bg-[#FDF2EC] min-h-[50px] p-2 lg:min-h-[40px] flex items-center justify-center"> + <div className="flex items-center"> + <Image + src={BannerWarningIcon} + alt="Warning Icon" + className="mr-2 text-sm" + /> + <p className="text-xs md:text-sm text-black text-center flex flex-col md:block"> + <strong className="block mb-1 md:mb-0 md:inline"> + Unbonding disabled during Phase-2 {network} Transition + <span className="hidden md:inline">:</span> + </strong>{" "} + <span className="block text-xs md:text-sm md:inline"> + To support a smooth transition of the {network} to Phase-2, + on-demand unbonding has been disabled until the phase-2 {network} + launch. + </span> + </p> + </div> + </div> + ); +}; diff --git a/src/app/page.tsx b/src/app/page.tsx index 9d63f6a0..e836d311 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,6 +7,7 @@ import { Suspense, useCallback, useEffect, useState } from "react"; import { useLocalStorage } from "usehooks-ts"; import { useTermsAcceptance } from "@/app/hooks/useAcceptTerms"; +import { shouldDisableUnbonding } from "@/config"; import { network } from "@/config/network.config"; import { getCurrentGlobalParamsVersion } from "@/utils/globalParams"; import { calculateDelegationsDiff } from "@/utils/local_storage/calculateDelegationsDiff"; @@ -32,10 +33,12 @@ import { LoadingView } from "./components/Loading/Loading"; import { ConnectModal } from "./components/Modals/ConnectModal"; import { ErrorModal } from "./components/Modals/ErrorModal"; import { FilterOrdinalsModal } from "./components/Modals/FilterOrdinalsModal"; +import { UnbondingDisabledModal } from "./components/Modals/UnbondingDisabledModal"; import { NetworkBadge } from "./components/NetworkBadge/NetworkBadge"; import { Staking } from "./components/Staking/Staking"; import { Stats } from "./components/Stats/Stats"; import { Summary } from "./components/Summary/Summary"; +import { UnbondingDisabledBanner } from "./components/UnbondingDisabledBanner/UnbondingDisabledBanner"; import { useError } from "./context/Error/ErrorContext"; import { Delegation, DelegationState } from "./types/delegations"; import { ErrorState } from "./types/errors"; @@ -357,6 +360,7 @@ const Home: React.FC<HomeProps> = () => { className={`relative h-full min-h-svh w-full ${network === Network.MAINNET ? "main-app-mainnet" : "main-app-testnet"}`} > <NetworkBadge isWalletConnected={!!btcWallet} /> + {shouldDisableUnbonding() && <UnbondingDisabledBanner />} <Header onConnect={handleConnectModal} onDisconnect={handleDisconnectBTC} @@ -444,6 +448,7 @@ const Home: React.FC<HomeProps> = () => { onRetry={retryErrorAction} noCancel={noCancel} /> + <UnbondingDisabledModal /> </main> ); }; diff --git a/src/config/index.ts b/src/config/index.ts index e8670507..292c4a9f 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -18,3 +18,9 @@ export const getNetworkAppUrl = (): string => { export const shouldDisplayPoints = (): boolean => { return !!process.env.NEXT_PUBLIC_POINTS_API_URL; }; + +// shouldDisableUnbonding function is used to check if the application should +// disable unbonding or not based on the existence of the environment variable. +export const shouldDisableUnbonding = (): boolean => { + return process.env.NEXT_PUBLIC_DISABLE_UNBONDING?.toString() === "true"; +};