From 0c49175839b96ef7e306676237861ede3b87fc34 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Thu, 9 May 2024 10:47:54 +0200 Subject: [PATCH 01/13] Move data from context to redux for action flow --- .../TransactionModal/ActiveFlowStep.tsx | 11 ++++- .../ActiveStakingStep/DepositBTCModal.tsx | 9 ++-- .../StakingErrorModal/index.tsx | 10 ++--- .../ActiveUnstakingStep/SignMessageModal.tsx | 11 +++-- .../TransactionModal/ModalContentWrapper.tsx | 6 ++- .../src/components/TransactionModal/index.tsx | 30 ++++---------- dapp/src/contexts/ModalFlowContext.tsx | 6 --- dapp/src/hooks/store/index.ts | 3 ++ .../hooks/store/useActionFlowActiveStep.ts | 6 +++ dapp/src/hooks/store/useActionFlowStatus.ts | 6 +++ dapp/src/hooks/store/useActionFlowType.ts | 6 +++ .../store/action-flow/actionFlowSelectors.ts | 11 +++++ dapp/src/store/action-flow/actionFlowSlice.ts | 41 +++++++++++++++++++ dapp/src/store/action-flow/index.ts | 2 + dapp/src/store/reducer.ts | 2 + 15 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 dapp/src/hooks/store/useActionFlowActiveStep.ts create mode 100644 dapp/src/hooks/store/useActionFlowStatus.ts create mode 100644 dapp/src/hooks/store/useActionFlowType.ts create mode 100644 dapp/src/store/action-flow/actionFlowSelectors.ts create mode 100644 dapp/src/store/action-flow/actionFlowSlice.ts create mode 100644 dapp/src/store/action-flow/index.ts diff --git a/dapp/src/components/TransactionModal/ActiveFlowStep.tsx b/dapp/src/components/TransactionModal/ActiveFlowStep.tsx index 0e27f2f74..5465363af 100644 --- a/dapp/src/components/TransactionModal/ActiveFlowStep.tsx +++ b/dapp/src/components/TransactionModal/ActiveFlowStep.tsx @@ -1,5 +1,9 @@ import React, { ReactElement, useEffect } from "react" -import { useModalFlowContext } from "#/hooks" +import { + useModalFlowContext, + useActionFlowActiveStep, + useActionFlowType, +} from "#/hooks" import { ACTION_FLOW_STEPS_TYPES, ActionFlowType, @@ -18,7 +22,10 @@ const FLOW: Record ReactElement> = { } export function ActiveFlowStep() { - const { activeStep, type, onClose } = useModalFlowContext() + const { onClose } = useModalFlowContext() + const activeStep = useActionFlowActiveStep() + const type = useActionFlowType() + const numberOfSteps = Object.keys(ACTION_FLOW_STEPS_TYPES[type]).length useEffect(() => { diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx index 1878b03c3..0940b2f63 100644 --- a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx @@ -3,7 +3,6 @@ import { useDepositBTCTransaction, useDepositTelemetry, useExecuteFunction, - useModalFlowContext, useStakeFlowContext, useToast, useTransactionContext, @@ -17,6 +16,7 @@ import Spinner from "#/components/shared/Spinner" import { TextMd } from "#/components/shared/Typography" import { CardAlert } from "#/components/shared/alerts" import { ONE_SEC_IN_MILLISECONDS } from "#/constants" +import { setStatus } from "#/store/action-flow" const DELAY = ONE_SEC_IN_MILLISECONDS * 2 const TOAST_ID = TOAST_IDS.DEPOSIT_TRANSACTION_ERROR @@ -25,19 +25,18 @@ const TOAST = TOASTS[TOAST_ID] export default function DepositBTCModal() { const { ethAccount } = useWalletContext() const { tokenAmount } = useTransactionContext() - const { setStatus } = useModalFlowContext() const { btcAddress, depositReceipt, stake } = useStakeFlowContext() const depositTelemetry = useDepositTelemetry() const { closeToast, openToast } = useToast() const onStakeBTCSuccess = useCallback( () => setStatus(PROCESS_STATUSES.SUCCEEDED), - [setStatus], + [], ) const onStakeBTCError = useCallback(() => { setStatus(PROCESS_STATUSES.FAILED) - }, [setStatus]) + }, []) const handleStake = useExecuteFunction( stake, @@ -50,7 +49,7 @@ export default function DepositBTCModal() { setStatus(PROCESS_STATUSES.LOADING) logPromiseFailure(handleStake()) - }, [closeToast, setStatus, handleStake]) + }, [closeToast, handleStake]) const showError = useCallback(() => { openToast({ diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/index.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/index.tsx index 6ae4e1276..1473e50ef 100644 --- a/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/index.tsx +++ b/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/index.tsx @@ -1,17 +1,13 @@ import React, { useCallback, useState } from "react" -import { - useExecuteFunction, - useModalFlowContext, - useStakeFlowContext, -} from "#/hooks" +import { useExecuteFunction, useStakeFlowContext } from "#/hooks" import { PROCESS_STATUSES } from "#/types" import { logPromiseFailure } from "#/utils" +import { setStatus } from "#/store/action-flow" import ServerErrorModal from "./ServerErrorModal" import RetryModal from "./RetryModal" import LoadingModal from "../../LoadingModal" export default function StakingErrorModal() { - const { setStatus } = useModalFlowContext() const { stake } = useStakeFlowContext() const [isLoading, setIsLoading] = useState(false) @@ -19,7 +15,7 @@ export default function StakingErrorModal() { const onStakeBTCSuccess = useCallback( () => setStatus(PROCESS_STATUSES.SUCCEEDED), - [setStatus], + [], ) const onStakeBTCError = useCallback(() => setIsServerError(true), []) diff --git a/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx b/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx index e46359396..e05bc5bec 100644 --- a/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx @@ -1,21 +1,20 @@ import React, { useCallback } from "react" -import { useExecuteFunction, useModalFlowContext } from "#/hooks" +import { useExecuteFunction } from "#/hooks" import { PROCESS_STATUSES } from "#/types" import { Button, ModalBody, ModalFooter, ModalHeader } from "@chakra-ui/react" import { TextMd } from "#/components/shared/Typography" import { logPromiseFailure } from "#/utils" +import { setStatus } from "#/store/action-flow" export default function SignMessageModal() { - const { setStatus } = useModalFlowContext() - const onSignMessageSuccess = useCallback(() => { setStatus(PROCESS_STATUSES.SUCCEEDED) - }, [setStatus]) + }, []) // TODO: After a failed attempt, we should display the message const onSignMessageError = useCallback(() => { setStatus(PROCESS_STATUSES.FAILED) - }, [setStatus]) + }, []) const handleSignMessage = useExecuteFunction( // TODO: Use a correct function from the SDK @@ -31,7 +30,7 @@ export default function SignMessageModal() { setTimeout(() => { logPromiseFailure(handleSignMessage()) }, 5000) - }, [setStatus, handleSignMessage]) + }, [handleSignMessage]) return ( <> diff --git a/dapp/src/components/TransactionModal/ModalContentWrapper.tsx b/dapp/src/components/TransactionModal/ModalContentWrapper.tsx index 776b36ec3..914acf999 100644 --- a/dapp/src/components/TransactionModal/ModalContentWrapper.tsx +++ b/dapp/src/components/TransactionModal/ModalContentWrapper.tsx @@ -1,6 +1,7 @@ import React from "react" import { - useModalFlowContext, + useActionFlowStatus, + useActionFlowType, useRequestBitcoinAccount, useRequestEthereumAccount, useTransactionContext, @@ -23,7 +24,8 @@ export default function ModalContentWrapper({ const { btcAccount, ethAccount } = useWalletContext() const { requestAccount: requestBitcoinAccount } = useRequestBitcoinAccount() const { requestAccount: requestEthereumAccount } = useRequestEthereumAccount() - const { type, status } = useModalFlowContext() + const status = useActionFlowStatus() + const type = useActionFlowType() const { tokenAmount } = useTransactionContext() if (!btcAccount || !isSupportedBTCAddressType(btcAccount.address)) diff --git a/dapp/src/components/TransactionModal/index.tsx b/dapp/src/components/TransactionModal/index.tsx index 545417ef3..803712f78 100644 --- a/dapp/src/components/TransactionModal/index.tsx +++ b/dapp/src/components/TransactionModal/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useMemo, useState } from "react" +import React, { useEffect, useMemo } from "react" import { ModalFlowContext, ModalFlowContextValue, @@ -6,14 +6,13 @@ import { TransactionContextProvider, } from "#/contexts" import { useSidebar } from "#/hooks" -import { ActionFlowType, PROCESS_STATUSES, ProcessStatus } from "#/types" +import { ActionFlowType } from "#/types" import { ModalCloseButton } from "@chakra-ui/react" +import { resetState, setType } from "#/store/action-flow" import ModalBase from "../shared/ModalBase" import ModalContentWrapper from "./ModalContentWrapper" import { ActiveFlowStep } from "./ActiveFlowStep" -const DEFAULT_ACTIVE_STEP = 1 - type TransactionModalProps = { type: ActionFlowType isOpen: boolean @@ -27,17 +26,9 @@ export default function TransactionModal({ }: TransactionModalProps) { const { onOpen: openSideBar, onClose: closeSidebar } = useSidebar() - const [activeStep, setActiveStep] = useState(DEFAULT_ACTIVE_STEP) - const [status, setStatus] = useState(PROCESS_STATUSES.IDLE) - - const handleGoNext = useCallback(() => { - setActiveStep((prevStep) => prevStep + 1) - }, []) - - const resetState = useCallback(() => { - setActiveStep(DEFAULT_ACTIVE_STEP) - setStatus(PROCESS_STATUSES.IDLE) - }, [setStatus]) + useEffect(() => { + setType(type) + }, [type]) useEffect(() => { let timeout: NodeJS.Timeout @@ -49,18 +40,13 @@ export default function TransactionModal({ timeout = setTimeout(resetState, 100) } return () => clearTimeout(timeout) - }, [isOpen, resetState, openSideBar, closeSidebar]) + }, [isOpen, openSideBar, closeSidebar]) const contextValue: ModalFlowContextValue = useMemo( () => ({ - type, - activeStep, - status, - setStatus, onClose, - goNext: handleGoNext, }), - [type, activeStep, status, onClose, handleGoNext], + [onClose], ) return ( diff --git a/dapp/src/contexts/ModalFlowContext.tsx b/dapp/src/contexts/ModalFlowContext.tsx index 87f3754c9..df0d9363f 100644 --- a/dapp/src/contexts/ModalFlowContext.tsx +++ b/dapp/src/contexts/ModalFlowContext.tsx @@ -1,13 +1,7 @@ -import { ActionFlowType, ProcessStatus } from "#/types" import { createContext } from "react" export type ModalFlowContextValue = { - type: ActionFlowType - activeStep: number - status: ProcessStatus onClose: () => void - goNext: () => void - setStatus: React.Dispatch> } export const ModalFlowContext = createContext< diff --git a/dapp/src/hooks/store/index.ts b/dapp/src/hooks/store/index.ts index bdad282f8..9e114aada 100644 --- a/dapp/src/hooks/store/index.ts +++ b/dapp/src/hooks/store/index.ts @@ -3,3 +3,6 @@ export * from "./useAppSelector" export * from "./useEstimatedBTCBalance" export * from "./useSharesBalance" export * from "./useMinDepositAmount" +export * from "./useActionFlowType" +export * from "./useActionFlowStatus" +export * from "./useActionFlowActiveStep" diff --git a/dapp/src/hooks/store/useActionFlowActiveStep.ts b/dapp/src/hooks/store/useActionFlowActiveStep.ts new file mode 100644 index 000000000..f59e88bf4 --- /dev/null +++ b/dapp/src/hooks/store/useActionFlowActiveStep.ts @@ -0,0 +1,6 @@ +import { selectActionFlowActiveStep } from "#/store/action-flow" +import { useAppSelector } from "./useAppSelector" + +export function useActionFlowActiveStep() { + return useAppSelector(selectActionFlowActiveStep) +} diff --git a/dapp/src/hooks/store/useActionFlowStatus.ts b/dapp/src/hooks/store/useActionFlowStatus.ts new file mode 100644 index 000000000..5fb18915d --- /dev/null +++ b/dapp/src/hooks/store/useActionFlowStatus.ts @@ -0,0 +1,6 @@ +import { selectActionFlowStatus } from "#/store/action-flow" +import { useAppSelector } from "./useAppSelector" + +export function useActionFlowStatus() { + return useAppSelector(selectActionFlowStatus) +} diff --git a/dapp/src/hooks/store/useActionFlowType.ts b/dapp/src/hooks/store/useActionFlowType.ts new file mode 100644 index 000000000..c2b0d3c65 --- /dev/null +++ b/dapp/src/hooks/store/useActionFlowType.ts @@ -0,0 +1,6 @@ +import { selectActionFlowType } from "#/store/action-flow" +import { useAppSelector } from "./useAppSelector" + +export function useActionFlowType() { + return useAppSelector(selectActionFlowType) +} diff --git a/dapp/src/store/action-flow/actionFlowSelectors.ts b/dapp/src/store/action-flow/actionFlowSelectors.ts new file mode 100644 index 000000000..6de0a44bb --- /dev/null +++ b/dapp/src/store/action-flow/actionFlowSelectors.ts @@ -0,0 +1,11 @@ +import { ActionFlowType, ProcessStatus } from "#/types" +import { RootState } from ".." + +export const selectActionFlowType = (state: RootState): ActionFlowType => + state.actionFlow.type + +export const selectActionFlowActiveStep = (state: RootState): number => + state.actionFlow.activeStep + +export const selectActionFlowStatus = (state: RootState): ProcessStatus => + state.actionFlow.status diff --git a/dapp/src/store/action-flow/actionFlowSlice.ts b/dapp/src/store/action-flow/actionFlowSlice.ts new file mode 100644 index 000000000..6a3b8a721 --- /dev/null +++ b/dapp/src/store/action-flow/actionFlowSlice.ts @@ -0,0 +1,41 @@ +import { ActionFlowType, PROCESS_STATUSES, ProcessStatus } from "#/types" +import { PayloadAction, createSlice } from "@reduxjs/toolkit" + +type ActionFlowState = { + type: ActionFlowType + activeStep: number + status: ProcessStatus +} + +const initialState: ActionFlowState = { + type: "stake", + activeStep: 1, + status: PROCESS_STATUSES.IDLE, +} + +export const actionFlowSlice = createSlice({ + name: "action-flow", + initialState, + reducers: { + setType(state, action: PayloadAction) { + state.type = action.payload + }, + setActiveStep(state, action: PayloadAction) { + state.activeStep = action.payload + }, + setStatus(state, action: PayloadAction) { + state.status = action.payload + }, + goNextStep(state) { + state.activeStep += 1 + }, + resetState(state) { + state.type = initialState.type + state.activeStep = initialState.activeStep + state.status = initialState.status + }, + }, +}) + +export const { setType, setStatus, goNextStep, resetState } = + actionFlowSlice.actions diff --git a/dapp/src/store/action-flow/index.ts b/dapp/src/store/action-flow/index.ts new file mode 100644 index 000000000..261659e2f --- /dev/null +++ b/dapp/src/store/action-flow/index.ts @@ -0,0 +1,2 @@ +export * from "./actionFlowSlice" +export * from "./actionFlowSelectors" diff --git a/dapp/src/store/reducer.ts b/dapp/src/store/reducer.ts index a49f551e8..6ed0155e2 100644 --- a/dapp/src/store/reducer.ts +++ b/dapp/src/store/reducer.ts @@ -1,6 +1,8 @@ import { combineReducers } from "@reduxjs/toolkit" import { btcSlice } from "./btc/btcSlice" +import { actionFlowSlice } from "./action-flow/actionFlowSlice" export const reducer = combineReducers({ btc: btcSlice.reducer, + actionFlow: actionFlowSlice.reducer, }) From a38eb0fb3318ac99b3935317ea11c77cf49a76cc Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Thu, 9 May 2024 12:53:14 +0200 Subject: [PATCH 02/13] Simplifying the logic for opening modals Modal is a global component and should be rendered on the top of the components tree. It shouldn't be rendered from the `PositionDetails` level. --- dapp/src/DApp.tsx | 2 + dapp/src/components/ModalRoot/index.tsx | 19 ++++++ .../components/ModalRoot/withBaseModal.tsx | 28 ++++++++ .../TransactionModal/ActiveFlowStep.tsx | 12 ++-- .../StakingErrorModal/ServerErrorModal.tsx | 2 +- .../TransactionModal/SuccessModal.tsx | 6 +- .../src/components/TransactionModal/index.tsx | 68 ++++++------------- .../src/components/shared/ModalBase/index.tsx | 13 ---- dapp/src/contexts/ModalFlowContext.tsx | 9 --- dapp/src/contexts/index.tsx | 1 - dapp/src/hooks/index.ts | 2 +- dapp/src/hooks/useModal.ts | 27 ++++++++ dapp/src/hooks/useModalFlowContext.ts | 14 ---- .../pages/OverviewPage/PositionDetails.tsx | 31 ++------- dapp/src/store/modal/index.ts | 2 + dapp/src/store/modal/modalSelectors.ts | 8 +++ dapp/src/store/modal/modalSlice.ts | 32 +++++++++ dapp/src/store/reducer.ts | 2 + dapp/src/types/index.ts | 1 + dapp/src/types/modal.ts | 12 ++++ 20 files changed, 169 insertions(+), 122 deletions(-) create mode 100644 dapp/src/components/ModalRoot/index.tsx create mode 100644 dapp/src/components/ModalRoot/withBaseModal.tsx delete mode 100644 dapp/src/components/shared/ModalBase/index.tsx delete mode 100644 dapp/src/contexts/ModalFlowContext.tsx create mode 100644 dapp/src/hooks/useModal.ts delete mode 100644 dapp/src/hooks/useModalFlowContext.ts create mode 100644 dapp/src/store/modal/index.ts create mode 100644 dapp/src/store/modal/modalSelectors.ts create mode 100644 dapp/src/store/modal/modalSlice.ts create mode 100644 dapp/src/types/modal.ts diff --git a/dapp/src/DApp.tsx b/dapp/src/DApp.tsx index 71db1bc16..97e513488 100644 --- a/dapp/src/DApp.tsx +++ b/dapp/src/DApp.tsx @@ -17,6 +17,7 @@ import Sidebar from "./components/Sidebar" import DocsDrawer from "./components/DocsDrawer" import GlobalStyles from "./components/GlobalStyles" import { router } from "./router" +import ModalRoot from "./components/ModalRoot" function DApp() { useInitApp() @@ -29,6 +30,7 @@ function DApp() { + ) } diff --git a/dapp/src/components/ModalRoot/index.tsx b/dapp/src/components/ModalRoot/index.tsx new file mode 100644 index 000000000..22e6187f5 --- /dev/null +++ b/dapp/src/components/ModalRoot/index.tsx @@ -0,0 +1,19 @@ +import React, { ElementType } from "react" +import { useModal } from "#/hooks" +import { ModalType } from "#/types" +import TransactionModal from "../TransactionModal" + +const MODALS: Record = { + STAKE: TransactionModal, + UNSTAKE: TransactionModal, +} as const + +export default function ModalRoot() { + const { modalType, modalProps, closeModal } = useModal() + + if (!modalType) { + return null + } + const SpecificModal = MODALS[modalType] + return +} diff --git a/dapp/src/components/ModalRoot/withBaseModal.tsx b/dapp/src/components/ModalRoot/withBaseModal.tsx new file mode 100644 index 000000000..f0c24a99f --- /dev/null +++ b/dapp/src/components/ModalRoot/withBaseModal.tsx @@ -0,0 +1,28 @@ +import React, { ComponentType } from "react" +import { Modal, ModalContent, ModalOverlay } from "@chakra-ui/react" +import { BaseModalProps } from "#/types" + +export const MODAL_BASE_SIZE = "lg" + +function withBaseModal( + WrappedModalContent: ComponentType, +) { + return function ModalBase(props: T) { + const { closeModal } = props + return ( + + + + + + + ) + } +} + +export default withBaseModal diff --git a/dapp/src/components/TransactionModal/ActiveFlowStep.tsx b/dapp/src/components/TransactionModal/ActiveFlowStep.tsx index 5465363af..bf8e5eafa 100644 --- a/dapp/src/components/TransactionModal/ActiveFlowStep.tsx +++ b/dapp/src/components/TransactionModal/ActiveFlowStep.tsx @@ -1,9 +1,5 @@ import React, { ReactElement, useEffect } from "react" -import { - useModalFlowContext, - useActionFlowActiveStep, - useActionFlowType, -} from "#/hooks" +import { useActionFlowActiveStep, useActionFlowType, useModal } from "#/hooks" import { ACTION_FLOW_STEPS_TYPES, ActionFlowType, @@ -22,7 +18,7 @@ const FLOW: Record ReactElement> = { } export function ActiveFlowStep() { - const { onClose } = useModalFlowContext() + const { closeModal } = useModal() const activeStep = useActionFlowActiveStep() const type = useActionFlowType() @@ -30,9 +26,9 @@ export function ActiveFlowStep() { useEffect(() => { if (activeStep > numberOfSteps) { - onClose() + closeModal() } - }, [activeStep, numberOfSteps, onClose]) + }, [activeStep, closeModal, numberOfSteps]) return FLOW[type](activeStep) } diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/ServerErrorModal.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/ServerErrorModal.tsx index 179c0d62c..e83409338 100644 --- a/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/ServerErrorModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/ServerErrorModal.tsx @@ -15,7 +15,7 @@ import { CableWithPlugIcon, Info } from "#/assets/icons" import { TextMd } from "#/components/shared/Typography" import { EXTERNAL_HREF } from "#/constants" import IconWrapper from "#/components/shared/IconWrapper" -import { MODAL_BASE_SIZE } from "#/components/shared/ModalBase" +import { MODAL_BASE_SIZE } from "#/components/ModalRoot/withBaseModal" import { IconBrandDiscordFilled, IconReload, diff --git a/dapp/src/components/TransactionModal/SuccessModal.tsx b/dapp/src/components/TransactionModal/SuccessModal.tsx index 2c2a2c5de..3e873612a 100644 --- a/dapp/src/components/TransactionModal/SuccessModal.tsx +++ b/dapp/src/components/TransactionModal/SuccessModal.tsx @@ -9,7 +9,7 @@ import { VStack, } from "@chakra-ui/react" import { LoadingSpinnerSuccessIcon } from "#/assets/icons" -import { useModalFlowContext } from "#/hooks" +import { useModal } from "#/hooks" import { CurrencyBalanceWithConversion } from "#/components/shared/CurrencyBalanceWithConversion" import { ACTION_FLOW_TYPES, ActionFlowType, TokenAmount } from "#/types" import { TextMd } from "../shared/Typography" @@ -67,7 +67,7 @@ type SuccessModalProps = { } export default function SuccessModal({ type, tokenAmount }: SuccessModalProps) { - const { onClose } = useModalFlowContext() + const { closeModal } = useModal() const { header, footer, renderBody } = CONTENT[type] @@ -81,7 +81,7 @@ export default function SuccessModal({ type, tokenAmount }: SuccessModalProps) { - diff --git a/dapp/src/components/TransactionModal/index.tsx b/dapp/src/components/TransactionModal/index.tsx index 803712f78..13f6ed82d 100644 --- a/dapp/src/components/TransactionModal/index.tsx +++ b/dapp/src/components/TransactionModal/index.tsx @@ -1,29 +1,18 @@ -import React, { useEffect, useMemo } from "react" -import { - ModalFlowContext, - ModalFlowContextValue, - StakeFlowProvider, - TransactionContextProvider, -} from "#/contexts" +import React, { useEffect } from "react" +import { StakeFlowProvider, TransactionContextProvider } from "#/contexts" import { useSidebar } from "#/hooks" -import { ActionFlowType } from "#/types" +import { ActionFlowType, BaseModalProps } from "#/types" import { ModalCloseButton } from "@chakra-ui/react" -import { resetState, setType } from "#/store/action-flow" -import ModalBase from "../shared/ModalBase" +import { setType } from "#/store/action-flow" import ModalContentWrapper from "./ModalContentWrapper" import { ActiveFlowStep } from "./ActiveFlowStep" +import withBaseModal from "../ModalRoot/withBaseModal" type TransactionModalProps = { type: ActionFlowType - isOpen: boolean - onClose: () => void -} +} & BaseModalProps -export default function TransactionModal({ - type, - isOpen, - onClose, -}: TransactionModalProps) { +function TransactionModalBase({ type }: TransactionModalProps) { const { onOpen: openSideBar, onClose: closeSidebar } = useSidebar() useEffect(() => { @@ -31,36 +20,21 @@ export default function TransactionModal({ }, [type]) useEffect(() => { - let timeout: NodeJS.Timeout - - if (isOpen) { - openSideBar() - } else { - closeSidebar() - timeout = setTimeout(resetState, 100) - } - return () => clearTimeout(timeout) - }, [isOpen, openSideBar, closeSidebar]) - - const contextValue: ModalFlowContextValue = useMemo( - () => ({ - onClose, - }), - [onClose], - ) + openSideBar() + return () => closeSidebar() + }, [closeSidebar, openSideBar]) return ( - - - - - - - - - - - - + + + + + + + + ) } + +const TransactionModal = withBaseModal(TransactionModalBase) +export default TransactionModal diff --git a/dapp/src/components/shared/ModalBase/index.tsx b/dapp/src/components/shared/ModalBase/index.tsx deleted file mode 100644 index 416b22850..000000000 --- a/dapp/src/components/shared/ModalBase/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react" -import { Modal, ModalContent, ModalOverlay, ModalProps } from "@chakra-ui/react" - -export const MODAL_BASE_SIZE = "lg" - -export default function ModalBase({ children, ...restProps }: ModalProps) { - return ( - - - {children} - - ) -} diff --git a/dapp/src/contexts/ModalFlowContext.tsx b/dapp/src/contexts/ModalFlowContext.tsx deleted file mode 100644 index df0d9363f..000000000 --- a/dapp/src/contexts/ModalFlowContext.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createContext } from "react" - -export type ModalFlowContextValue = { - onClose: () => void -} - -export const ModalFlowContext = createContext< - ModalFlowContextValue | undefined ->(undefined) diff --git a/dapp/src/contexts/index.tsx b/dapp/src/contexts/index.tsx index 47a8cd708..a3365497c 100644 --- a/dapp/src/contexts/index.tsx +++ b/dapp/src/contexts/index.tsx @@ -3,6 +3,5 @@ export * from "./WalletApiReactTransportProvider" export * from "./LedgerWalletAPIProvider" export * from "./DocsDrawerContext" export * from "./SidebarContext" -export * from "./ModalFlowContext" export * from "./TransactionContext" export * from "./StakeFlowContext" diff --git a/dapp/src/hooks/index.ts b/dapp/src/hooks/index.ts index 1c483932d..b5f482748 100644 --- a/dapp/src/hooks/index.ts +++ b/dapp/src/hooks/index.ts @@ -7,7 +7,6 @@ export * from "./useRequestEthereumAccount" export * from "./useWalletContext" export * from "./useSidebar" export * from "./useDocsDrawer" -export * from "./useModalFlowContext" export * from "./useTransactionContext" export * from "./useTransactionDetails" export * from "./useDepositBTCTransaction" @@ -24,3 +23,4 @@ export * from "./useCountdown" export * from "./useActivities" export * from "./useSize" export * from "./useTransactionFee" +export * from "./useModal" diff --git a/dapp/src/hooks/useModal.ts b/dapp/src/hooks/useModal.ts new file mode 100644 index 000000000..8d213e785 --- /dev/null +++ b/dapp/src/hooks/useModal.ts @@ -0,0 +1,27 @@ +import { + closeModal, + openModal, + selectModalProps, + selectModalType, +} from "#/store/modal" +import { ModalProps, ModalType } from "#/types" +import { useAppDispatch } from "./store/useAppDispatch" +import { useAppSelector } from "./store/useAppSelector" + +export function useModal() { + const modalType = useAppSelector(selectModalType) + const modalProps = useAppSelector(selectModalProps) + const dispatch = useAppDispatch() + + const handleOpenModal = (type: ModalType, props?: ModalProps) => + dispatch(openModal({ modalType: type, props })) + + const handleCloseModal = () => dispatch(closeModal()) + + return { + modalType, + modalProps, + openModal: handleOpenModal, + closeModal: handleCloseModal, + } +} diff --git a/dapp/src/hooks/useModalFlowContext.ts b/dapp/src/hooks/useModalFlowContext.ts deleted file mode 100644 index fda6eb681..000000000 --- a/dapp/src/hooks/useModalFlowContext.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from "react" -import { ModalFlowContext } from "#/contexts" - -export function useModalFlowContext() { - const context = useContext(ModalFlowContext) - - if (!context) { - throw new Error( - "ModalFlowContext used outside of ModalFlowContext component", - ) - } - - return context -} diff --git a/dapp/src/pages/OverviewPage/PositionDetails.tsx b/dapp/src/pages/OverviewPage/PositionDetails.tsx index 179f46c6d..8a432b9f1 100644 --- a/dapp/src/pages/OverviewPage/PositionDetails.tsx +++ b/dapp/src/pages/OverviewPage/PositionDetails.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from "react" +import React from "react" import { Button, CardBody, @@ -9,23 +9,15 @@ import { } from "@chakra-ui/react" import { CurrencyBalanceWithConversion } from "#/components/shared/CurrencyBalanceWithConversion" import { TextMd } from "#/components/shared/Typography" -import { ACTION_FLOW_TYPES, ActionFlowType } from "#/types" -import TransactionModal from "#/components/TransactionModal" +import { MODAL_TYPES } from "#/types" import { useEstimatedBTCBalance } from "#/hooks/store" import { LiquidStakingTokenPopover } from "#/components/LiquidStakingTokenPopover" -import { useSize } from "#/hooks" +import { useModal, useSize } from "#/hooks" export default function PositionDetails(props: CardProps) { const estimatedBtcBalance = useEstimatedBTCBalance() const { ref, size } = useSize() - - const [actionFlowType, setActionFlowType] = useState< - ActionFlowType | undefined - >(undefined) - - const handleCloseTransactionModal = useCallback(() => { - setActionFlowType(undefined) - }, []) + const { openModal } = useModal() return ( @@ -50,29 +42,18 @@ export default function PositionDetails(props: CardProps) { - {/* TODO: Simplify the logic of opening modals */} - - ) } diff --git a/dapp/src/store/modal/index.ts b/dapp/src/store/modal/index.ts new file mode 100644 index 000000000..06ad11596 --- /dev/null +++ b/dapp/src/store/modal/index.ts @@ -0,0 +1,2 @@ +export * from "./modalSlice" +export * from "./modalSelectors" diff --git a/dapp/src/store/modal/modalSelectors.ts b/dapp/src/store/modal/modalSelectors.ts new file mode 100644 index 000000000..39f642e8e --- /dev/null +++ b/dapp/src/store/modal/modalSelectors.ts @@ -0,0 +1,8 @@ +import { ModalProps, ModalType } from "#/types" +import { RootState } from ".." + +export const selectModalType = (state: RootState): ModalType | null => + state.modal.modalType + +export const selectModalProps = (state: RootState): ModalProps | undefined => + state.modal.props diff --git a/dapp/src/store/modal/modalSlice.ts b/dapp/src/store/modal/modalSlice.ts new file mode 100644 index 000000000..9877bfbd9 --- /dev/null +++ b/dapp/src/store/modal/modalSlice.ts @@ -0,0 +1,32 @@ +import { ModalType, ModalProps } from "#/types" +import { createSlice, PayloadAction } from "@reduxjs/toolkit" + +type ModalState = { + modalType: ModalType | null + props?: ModalProps +} + +const initialState: ModalState = { + modalType: null, + props: {}, +} + +export const modalSlice = createSlice({ + name: "modal", + initialState, + reducers: { + openModal: ( + state: ModalState, + action: PayloadAction<{ modalType: ModalType; props?: ModalProps }>, + ) => { + state.modalType = action.payload.modalType + state.props = action.payload.props + }, + closeModal: (state: ModalState) => { + state.modalType = null + state.props = {} + }, + }, +}) + +export const { openModal, closeModal } = modalSlice.actions diff --git a/dapp/src/store/reducer.ts b/dapp/src/store/reducer.ts index 6ed0155e2..1e15ef056 100644 --- a/dapp/src/store/reducer.ts +++ b/dapp/src/store/reducer.ts @@ -1,8 +1,10 @@ import { combineReducers } from "@reduxjs/toolkit" import { btcSlice } from "./btc/btcSlice" import { actionFlowSlice } from "./action-flow/actionFlowSlice" +import { modalSlice } from "./modal/modalSlice" export const reducer = combineReducers({ btc: btcSlice.reducer, actionFlow: actionFlowSlice.reducer, + modal: modalSlice.reducer, }) diff --git a/dapp/src/types/index.ts b/dapp/src/types/index.ts index b3b047b18..19adfd5ab 100644 --- a/dapp/src/types/index.ts +++ b/dapp/src/types/index.ts @@ -14,3 +14,4 @@ export * from "./time" export * from "./size" export * from "./toast" export * from "./fee" +export * from "./modal" diff --git a/dapp/src/types/modal.ts b/dapp/src/types/modal.ts new file mode 100644 index 000000000..75febc189 --- /dev/null +++ b/dapp/src/types/modal.ts @@ -0,0 +1,12 @@ +export type ModalProps = Record + +export type BaseModalProps = { + closeModal: () => void +} + +export const MODAL_TYPES = { + STAKE: "STAKE", + UNSTAKE: "UNSTAKE", +} as const + +export type ModalType = (typeof MODAL_TYPES)[keyof typeof MODAL_TYPES] From 5a3b4c7a5bbcd532ff785d6463c38a38fc113ad4 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Thu, 9 May 2024 14:25:11 +0200 Subject: [PATCH 03/13] Add ability to open `TransactionModal` from landing page --- .../pages/LandingPage/components/HeroSection.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dapp/src/pages/LandingPage/components/HeroSection.tsx b/dapp/src/pages/LandingPage/components/HeroSection.tsx index 14d8a7e4a..280f2a710 100644 --- a/dapp/src/pages/LandingPage/components/HeroSection.tsx +++ b/dapp/src/pages/LandingPage/components/HeroSection.tsx @@ -1,7 +1,11 @@ import React from "react" import { Button, Heading, VStack, Text } from "@chakra-ui/react" +import { useModal } from "#/hooks" +import { MODAL_TYPES } from "#/types" export default function HeroSection() { + const { openModal } = useModal() + return ( The open source, decentralized way to grow your bitcoin - From 1e64bc0abaf7a794e1332ec3738d4569555a2d08 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Thu, 9 May 2024 14:27:05 +0200 Subject: [PATCH 04/13] Fix issue with closing modal --- dapp/src/components/ModalRoot/withBaseModal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/dapp/src/components/ModalRoot/withBaseModal.tsx b/dapp/src/components/ModalRoot/withBaseModal.tsx index f0c24a99f..de804ca0d 100644 --- a/dapp/src/components/ModalRoot/withBaseModal.tsx +++ b/dapp/src/components/ModalRoot/withBaseModal.tsx @@ -14,6 +14,7 @@ function withBaseModal( isOpen onClose={closeModal} scrollBehavior="inside" + closeOnOverlayClick={false} size={MODAL_BASE_SIZE} > From b39b1200645c36b5fc26a126854b1056ba19a749 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Thu, 9 May 2024 15:06:00 +0200 Subject: [PATCH 05/13] Fix issue with switching type for action flow --- dapp/src/components/TransactionModal/index.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dapp/src/components/TransactionModal/index.tsx b/dapp/src/components/TransactionModal/index.tsx index 13f6ed82d..d6fd04303 100644 --- a/dapp/src/components/TransactionModal/index.tsx +++ b/dapp/src/components/TransactionModal/index.tsx @@ -1,9 +1,9 @@ import React, { useEffect } from "react" import { StakeFlowProvider, TransactionContextProvider } from "#/contexts" -import { useSidebar } from "#/hooks" +import { useAppDispatch, useSidebar } from "#/hooks" import { ActionFlowType, BaseModalProps } from "#/types" import { ModalCloseButton } from "@chakra-ui/react" -import { setType } from "#/store/action-flow" +import { resetState, setType } from "#/store/action-flow" import ModalContentWrapper from "./ModalContentWrapper" import { ActiveFlowStep } from "./ActiveFlowStep" import withBaseModal from "../ModalRoot/withBaseModal" @@ -14,10 +14,11 @@ type TransactionModalProps = { function TransactionModalBase({ type }: TransactionModalProps) { const { onOpen: openSideBar, onClose: closeSidebar } = useSidebar() + const dispatch = useAppDispatch() useEffect(() => { - setType(type) - }, [type]) + dispatch(setType(type)) + }, [dispatch, type]) useEffect(() => { openSideBar() From 5f9f85dd534ce05a3377f03f63de0660d343af65 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Fri, 10 May 2024 09:21:44 +0200 Subject: [PATCH 06/13] Reset state for `TransactionModal` --- dapp/src/components/TransactionModal/index.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dapp/src/components/TransactionModal/index.tsx b/dapp/src/components/TransactionModal/index.tsx index d6fd04303..5dc91b9f5 100644 --- a/dapp/src/components/TransactionModal/index.tsx +++ b/dapp/src/components/TransactionModal/index.tsx @@ -20,6 +20,13 @@ function TransactionModalBase({ type }: TransactionModalProps) { dispatch(setType(type)) }, [dispatch, type]) + // eslint-disable-next-line arrow-body-style + useEffect(() => { + return () => { + dispatch(resetState()) + } + }, [dispatch]) + useEffect(() => { openSideBar() return () => closeSidebar() From 15c3f9e96dcdcaba2781c219602521ca3dde045a Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Fri, 10 May 2024 09:23:45 +0200 Subject: [PATCH 07/13] Update value of delay for triggering Bitcoin transaction --- .../TransactionModal/ActiveStakingStep/DepositBTCModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx index 0940b2f63..3ef936def 100644 --- a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx @@ -18,7 +18,7 @@ import { CardAlert } from "#/components/shared/alerts" import { ONE_SEC_IN_MILLISECONDS } from "#/constants" import { setStatus } from "#/store/action-flow" -const DELAY = ONE_SEC_IN_MILLISECONDS * 2 +const DELAY = ONE_SEC_IN_MILLISECONDS const TOAST_ID = TOAST_IDS.DEPOSIT_TRANSACTION_ERROR const TOAST = TOASTS[TOAST_ID] From b9dd2d8a078b8afa237a949510694738fa2aebf6 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Fri, 10 May 2024 09:36:05 +0200 Subject: [PATCH 08/13] Move `TransactionContext` to redux store --- .../TransactionModal/ActionFormModal.tsx | 13 +++---- .../ActiveStakingStep/DepositBTCModal.tsx | 4 +-- .../TransactionModal/ModalContentWrapper.tsx | 4 +-- .../src/components/TransactionModal/index.tsx | 16 ++++----- dapp/src/contexts/TransactionContext.tsx | 36 ------------------- dapp/src/contexts/index.tsx | 1 - dapp/src/hooks/index.ts | 1 - dapp/src/hooks/store/index.ts | 1 + .../hooks/store/useActionFlowTokenAmount.ts | 6 ++++ dapp/src/hooks/useTransactionContext.ts | 14 -------- .../store/action-flow/actionFlowSelectors.ts | 6 +++- dapp/src/store/action-flow/actionFlowSlice.ts | 13 +++++-- 12 files changed, 39 insertions(+), 76 deletions(-) delete mode 100644 dapp/src/contexts/TransactionContext.tsx create mode 100644 dapp/src/hooks/store/useActionFlowTokenAmount.ts delete mode 100644 dapp/src/hooks/useTransactionContext.ts diff --git a/dapp/src/components/TransactionModal/ActionFormModal.tsx b/dapp/src/components/TransactionModal/ActionFormModal.tsx index e536d426e..e38c1684b 100644 --- a/dapp/src/components/TransactionModal/ActionFormModal.tsx +++ b/dapp/src/components/TransactionModal/ActionFormModal.tsx @@ -1,15 +1,12 @@ import React, { useCallback, useState } from "react" import { Box, ModalBody, ModalCloseButton, ModalHeader } from "@chakra-ui/react" -import { - useStakeFlowContext, - useTransactionContext, - useWalletContext, -} from "#/hooks" +import { useAppDispatch, useStakeFlowContext, useWalletContext } from "#/hooks" import { ACTION_FLOW_TYPES, ActionFlowType } from "#/types" import { TokenAmountFormValues } from "#/components/shared/TokenAmountForm/TokenAmountFormBase" import { logPromiseFailure } from "#/utils" import StakeFormModal from "./ActiveStakingStep/StakeFormModal" import UnstakeFormModal from "./ActiveUnstakingStep/UnstakeFormModal" +import { setTokenAmount } from "#/store/action-flow" const FORM_DATA: Record< ActionFlowType, @@ -34,8 +31,8 @@ const FORM_DATA: Record< function ActionFormModal({ type }: { type: ActionFlowType }) { const { btcAccount, ethAccount } = useWalletContext() - const { setTokenAmount } = useTransactionContext() const { initStake } = useStakeFlowContext() + const dispatch = useAppDispatch() const [isLoading, setIsLoading] = useState(false) @@ -59,14 +56,14 @@ function ActionFormModal({ type }: { type: ActionFlowType }) { // TODO: Init unstake flow if (type === ACTION_FLOW_TYPES.STAKE) await handleInitStake() - setTokenAmount({ amount: values.amount, currency: "bitcoin" }) + dispatch(setTokenAmount({ amount: values.amount, currency: "bitcoin" })) } catch (error) { console.error(error) } finally { setIsLoading(false) } }, - [handleInitStake, setTokenAmount, type], + [dispatch, handleInitStake, type], ) const handleSubmitFormWrapper = useCallback( diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx index 3ef936def..b6843ce9e 100644 --- a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx @@ -1,11 +1,11 @@ import React, { useCallback } from "react" import { + useActionFlowTokenAmount, useDepositBTCTransaction, useDepositTelemetry, useExecuteFunction, useStakeFlowContext, useToast, - useTransactionContext, useWalletContext, } from "#/hooks" import { logPromiseFailure } from "#/utils" @@ -24,7 +24,7 @@ const TOAST = TOASTS[TOAST_ID] export default function DepositBTCModal() { const { ethAccount } = useWalletContext() - const { tokenAmount } = useTransactionContext() + const tokenAmount = useActionFlowTokenAmount() const { btcAddress, depositReceipt, stake } = useStakeFlowContext() const depositTelemetry = useDepositTelemetry() const { closeToast, openToast } = useToast() diff --git a/dapp/src/components/TransactionModal/ModalContentWrapper.tsx b/dapp/src/components/TransactionModal/ModalContentWrapper.tsx index 914acf999..cfe99aea7 100644 --- a/dapp/src/components/TransactionModal/ModalContentWrapper.tsx +++ b/dapp/src/components/TransactionModal/ModalContentWrapper.tsx @@ -1,10 +1,10 @@ import React from "react" import { useActionFlowStatus, + useActionFlowTokenAmount, useActionFlowType, useRequestBitcoinAccount, useRequestEthereumAccount, - useTransactionContext, useWalletContext, } from "#/hooks" import { BitcoinIcon, EthereumIcon } from "#/assets/icons" @@ -26,7 +26,7 @@ export default function ModalContentWrapper({ const { requestAccount: requestEthereumAccount } = useRequestEthereumAccount() const status = useActionFlowStatus() const type = useActionFlowType() - const { tokenAmount } = useTransactionContext() + const tokenAmount = useActionFlowTokenAmount() if (!btcAccount || !isSupportedBTCAddressType(btcAccount.address)) return ( diff --git a/dapp/src/components/TransactionModal/index.tsx b/dapp/src/components/TransactionModal/index.tsx index 5dc91b9f5..7fc1c88ad 100644 --- a/dapp/src/components/TransactionModal/index.tsx +++ b/dapp/src/components/TransactionModal/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from "react" -import { StakeFlowProvider, TransactionContextProvider } from "#/contexts" +import { StakeFlowProvider } from "#/contexts" import { useAppDispatch, useSidebar } from "#/hooks" import { ActionFlowType, BaseModalProps } from "#/types" import { ModalCloseButton } from "@chakra-ui/react" @@ -33,14 +33,12 @@ function TransactionModalBase({ type }: TransactionModalProps) { }, [closeSidebar, openSideBar]) return ( - - - - - - - - + + + + + + ) } diff --git a/dapp/src/contexts/TransactionContext.tsx b/dapp/src/contexts/TransactionContext.tsx deleted file mode 100644 index 8105fc841..000000000 --- a/dapp/src/contexts/TransactionContext.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React, { createContext, useMemo, useState } from "react" -import { TokenAmount } from "#/types" - -type TransactionContextValue = { - tokenAmount?: TokenAmount - setTokenAmount: React.Dispatch> -} - -export const TransactionContext = createContext< - TransactionContextValue | undefined ->(undefined) - -export function TransactionContextProvider({ - children, -}: { - children: React.ReactNode -}): React.ReactElement { - const [tokenAmount, setTokenAmount] = useState( - undefined, - ) - - const contextValue: TransactionContextValue = - useMemo( - () => ({ - tokenAmount, - setTokenAmount, - }), - [tokenAmount], - ) - - return ( - - {children} - - ) -} diff --git a/dapp/src/contexts/index.tsx b/dapp/src/contexts/index.tsx index a3365497c..b4218417a 100644 --- a/dapp/src/contexts/index.tsx +++ b/dapp/src/contexts/index.tsx @@ -3,5 +3,4 @@ export * from "./WalletApiReactTransportProvider" export * from "./LedgerWalletAPIProvider" export * from "./DocsDrawerContext" export * from "./SidebarContext" -export * from "./TransactionContext" export * from "./StakeFlowContext" diff --git a/dapp/src/hooks/index.ts b/dapp/src/hooks/index.ts index 150dda613..b3405e7be 100644 --- a/dapp/src/hooks/index.ts +++ b/dapp/src/hooks/index.ts @@ -8,7 +8,6 @@ export * from "./useRequestEthereumAccount" export * from "./useWalletContext" export * from "./useSidebar" export * from "./useDocsDrawer" -export * from "./useTransactionContext" export * from "./useTransactionDetails" export * from "./useDepositBTCTransaction" export * from "./useTransactionHistoryTable" diff --git a/dapp/src/hooks/store/index.ts b/dapp/src/hooks/store/index.ts index 7c30653b6..396d4e68f 100644 --- a/dapp/src/hooks/store/index.ts +++ b/dapp/src/hooks/store/index.ts @@ -6,5 +6,6 @@ export * from "./useMinDepositAmount" export * from "./useActionFlowType" export * from "./useActionFlowStatus" export * from "./useActionFlowActiveStep" +export * from "./useActionFlowTokenAmount" // TODO: Rename when the old hook is deleted. export { useActivities as useActivitiesNEW } from "./useActivities" diff --git a/dapp/src/hooks/store/useActionFlowTokenAmount.ts b/dapp/src/hooks/store/useActionFlowTokenAmount.ts new file mode 100644 index 000000000..f580df058 --- /dev/null +++ b/dapp/src/hooks/store/useActionFlowTokenAmount.ts @@ -0,0 +1,6 @@ +import { selectActionFlowTokenAmount } from "#/store/action-flow" +import { useAppSelector } from "./useAppSelector" + +export function useActionFlowTokenAmount() { + return useAppSelector(selectActionFlowTokenAmount) +} diff --git a/dapp/src/hooks/useTransactionContext.ts b/dapp/src/hooks/useTransactionContext.ts deleted file mode 100644 index 41a8a8359..000000000 --- a/dapp/src/hooks/useTransactionContext.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from "react" -import { TransactionContext } from "#/contexts" - -export function useTransactionContext() { - const context = useContext(TransactionContext) - - if (!context) { - throw new Error( - "TransactionContext used outside of TransactionContext component", - ) - } - - return context -} diff --git a/dapp/src/store/action-flow/actionFlowSelectors.ts b/dapp/src/store/action-flow/actionFlowSelectors.ts index 6de0a44bb..a814d6290 100644 --- a/dapp/src/store/action-flow/actionFlowSelectors.ts +++ b/dapp/src/store/action-flow/actionFlowSelectors.ts @@ -1,4 +1,4 @@ -import { ActionFlowType, ProcessStatus } from "#/types" +import { ActionFlowType, ProcessStatus, TokenAmount } from "#/types" import { RootState } from ".." export const selectActionFlowType = (state: RootState): ActionFlowType => @@ -9,3 +9,7 @@ export const selectActionFlowActiveStep = (state: RootState): number => export const selectActionFlowStatus = (state: RootState): ProcessStatus => state.actionFlow.status + +export const selectActionFlowTokenAmount = ( + state: RootState, +): TokenAmount | undefined => state.actionFlow.tokenAmount diff --git a/dapp/src/store/action-flow/actionFlowSlice.ts b/dapp/src/store/action-flow/actionFlowSlice.ts index 6a3b8a721..1866699c8 100644 --- a/dapp/src/store/action-flow/actionFlowSlice.ts +++ b/dapp/src/store/action-flow/actionFlowSlice.ts @@ -1,10 +1,16 @@ -import { ActionFlowType, PROCESS_STATUSES, ProcessStatus } from "#/types" +import { + ActionFlowType, + PROCESS_STATUSES, + ProcessStatus, + TokenAmount, +} from "#/types" import { PayloadAction, createSlice } from "@reduxjs/toolkit" type ActionFlowState = { type: ActionFlowType activeStep: number status: ProcessStatus + tokenAmount?: TokenAmount } const initialState: ActionFlowState = { @@ -26,6 +32,9 @@ export const actionFlowSlice = createSlice({ setStatus(state, action: PayloadAction) { state.status = action.payload }, + setTokenAmount(state, action: PayloadAction) { + state.tokenAmount = action.payload + }, goNextStep(state) { state.activeStep += 1 }, @@ -37,5 +46,5 @@ export const actionFlowSlice = createSlice({ }, }) -export const { setType, setStatus, goNextStep, resetState } = +export const { setType, setStatus, setTokenAmount, goNextStep, resetState } = actionFlowSlice.actions From af3135a8d20979b1bc44b5ccac9839a50bc571cc Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Fri, 10 May 2024 09:44:38 +0200 Subject: [PATCH 09/13] Fix eslint issue with imports --- dapp/src/components/Layout.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dapp/src/components/Layout.tsx b/dapp/src/components/Layout.tsx index 528160b9c..43a0bc2d3 100644 --- a/dapp/src/components/Layout.tsx +++ b/dapp/src/components/Layout.tsx @@ -1,6 +1,5 @@ -import React from "react" +import React, { useState } from "react" import { AnimatePresence, motion, Variants } from "framer-motion" -import { useState } from "react" import { useLocation, useOutlet } from "react-router-dom" import DocsDrawer from "./DocsDrawer" import Header from "./Header" From 754f2b36e8725e9fcc48fb6bddf7766a835e5e93 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Fri, 10 May 2024 09:46:05 +0200 Subject: [PATCH 10/13] Fix issue with resetting state for deposit flow --- dapp/src/store/action-flow/actionFlowSlice.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dapp/src/store/action-flow/actionFlowSlice.ts b/dapp/src/store/action-flow/actionFlowSlice.ts index 1866699c8..a1fdf4c2f 100644 --- a/dapp/src/store/action-flow/actionFlowSlice.ts +++ b/dapp/src/store/action-flow/actionFlowSlice.ts @@ -17,6 +17,7 @@ const initialState: ActionFlowState = { type: "stake", activeStep: 1, status: PROCESS_STATUSES.IDLE, + tokenAmount: undefined, } export const actionFlowSlice = createSlice({ @@ -42,6 +43,7 @@ export const actionFlowSlice = createSlice({ state.type = initialState.type state.activeStep = initialState.activeStep state.status = initialState.status + state.tokenAmount = initialState.tokenAmount }, }, }) From 4b2d4ef7565dcabd6100a7024be53fce6cd1ef7a Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Fri, 10 May 2024 09:50:46 +0200 Subject: [PATCH 11/13] Fix eslint issue --- dapp/src/components/TransactionModal/ActionFormModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dapp/src/components/TransactionModal/ActionFormModal.tsx b/dapp/src/components/TransactionModal/ActionFormModal.tsx index e38c1684b..dff2cc2a8 100644 --- a/dapp/src/components/TransactionModal/ActionFormModal.tsx +++ b/dapp/src/components/TransactionModal/ActionFormModal.tsx @@ -4,9 +4,9 @@ import { useAppDispatch, useStakeFlowContext, useWalletContext } from "#/hooks" import { ACTION_FLOW_TYPES, ActionFlowType } from "#/types" import { TokenAmountFormValues } from "#/components/shared/TokenAmountForm/TokenAmountFormBase" import { logPromiseFailure } from "#/utils" +import { setTokenAmount } from "#/store/action-flow" import StakeFormModal from "./ActiveStakingStep/StakeFormModal" import UnstakeFormModal from "./ActiveUnstakingStep/UnstakeFormModal" -import { setTokenAmount } from "#/store/action-flow" const FORM_DATA: Record< ActionFlowType, From d86f928fbb2eb4d385390d09ee6140e7c3cf6368 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Fri, 10 May 2024 10:07:04 +0200 Subject: [PATCH 12/13] Fix issue for redux actions --- .../ActiveStakingStep/DepositBTCModal.tsx | 14 ++++++++------ .../StakingErrorModal/index.tsx | 11 ++++++++--- .../ActiveUnstakingStep/SignMessageModal.tsx | 16 +++++++++------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx index b6843ce9e..f3fb591e5 100644 --- a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx @@ -1,6 +1,7 @@ import React, { useCallback } from "react" import { useActionFlowTokenAmount, + useAppDispatch, useDepositBTCTransaction, useDepositTelemetry, useExecuteFunction, @@ -28,15 +29,16 @@ export default function DepositBTCModal() { const { btcAddress, depositReceipt, stake } = useStakeFlowContext() const depositTelemetry = useDepositTelemetry() const { closeToast, openToast } = useToast() + const dispatch = useAppDispatch() const onStakeBTCSuccess = useCallback( - () => setStatus(PROCESS_STATUSES.SUCCEEDED), - [], + () => dispatch(setStatus(PROCESS_STATUSES.SUCCEEDED)), + [dispatch], ) const onStakeBTCError = useCallback(() => { - setStatus(PROCESS_STATUSES.FAILED) - }, []) + dispatch(setStatus(PROCESS_STATUSES.FAILED)) + }, [dispatch]) const handleStake = useExecuteFunction( stake, @@ -46,10 +48,10 @@ export default function DepositBTCModal() { const onDepositBTCSuccess = useCallback(() => { closeToast(TOAST_ID) - setStatus(PROCESS_STATUSES.LOADING) + dispatch(setStatus(PROCESS_STATUSES.LOADING)) logPromiseFailure(handleStake()) - }, [closeToast, handleStake]) + }, [closeToast, dispatch, handleStake]) const showError = useCallback(() => { openToast({ diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/index.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/index.tsx index 1473e50ef..969a4e145 100644 --- a/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/index.tsx +++ b/dapp/src/components/TransactionModal/ActiveStakingStep/StakingErrorModal/index.tsx @@ -1,5 +1,9 @@ import React, { useCallback, useState } from "react" -import { useExecuteFunction, useStakeFlowContext } from "#/hooks" +import { + useAppDispatch, + useExecuteFunction, + useStakeFlowContext, +} from "#/hooks" import { PROCESS_STATUSES } from "#/types" import { logPromiseFailure } from "#/utils" import { setStatus } from "#/store/action-flow" @@ -9,13 +13,14 @@ import LoadingModal from "../../LoadingModal" export default function StakingErrorModal() { const { stake } = useStakeFlowContext() + const dispatch = useAppDispatch() const [isLoading, setIsLoading] = useState(false) const [isServerError, setIsServerError] = useState(false) const onStakeBTCSuccess = useCallback( - () => setStatus(PROCESS_STATUSES.SUCCEEDED), - [], + () => dispatch(setStatus(PROCESS_STATUSES.SUCCEEDED)), + [dispatch], ) const onStakeBTCError = useCallback(() => setIsServerError(true), []) diff --git a/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx b/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx index e05bc5bec..3a8950325 100644 --- a/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx @@ -1,5 +1,5 @@ import React, { useCallback } from "react" -import { useExecuteFunction } from "#/hooks" +import { useAppDispatch, useExecuteFunction } from "#/hooks" import { PROCESS_STATUSES } from "#/types" import { Button, ModalBody, ModalFooter, ModalHeader } from "@chakra-ui/react" import { TextMd } from "#/components/shared/Typography" @@ -7,14 +7,16 @@ import { logPromiseFailure } from "#/utils" import { setStatus } from "#/store/action-flow" export default function SignMessageModal() { + const dispatch = useAppDispatch() + const onSignMessageSuccess = useCallback(() => { - setStatus(PROCESS_STATUSES.SUCCEEDED) - }, []) + dispatch(setStatus(PROCESS_STATUSES.SUCCEEDED)) + }, [dispatch]) // TODO: After a failed attempt, we should display the message const onSignMessageError = useCallback(() => { - setStatus(PROCESS_STATUSES.FAILED) - }, []) + dispatch(setStatus(PROCESS_STATUSES.FAILED)) + }, [dispatch]) const handleSignMessage = useExecuteFunction( // TODO: Use a correct function from the SDK @@ -24,13 +26,13 @@ export default function SignMessageModal() { ) const handleSignMessageWrapper = useCallback(() => { - setStatus(PROCESS_STATUSES.LOADING) + dispatch(setStatus(PROCESS_STATUSES.LOADING)) // TODO: Remove when SDK is ready setTimeout(() => { logPromiseFailure(handleSignMessage()) }, 5000) - }, [handleSignMessage]) + }, [dispatch, handleSignMessage]) return ( <> From f03702bfe67526341962906df89f9ea70c2de89e Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Wed, 15 May 2024 07:22:41 +0200 Subject: [PATCH 13/13] Open `TransactionModal` from new dashboard --- dapp/src/pages/DashboardPage/DashboardCard.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dapp/src/pages/DashboardPage/DashboardCard.tsx b/dapp/src/pages/DashboardPage/DashboardCard.tsx index 5b97bd116..459132cc8 100644 --- a/dapp/src/pages/DashboardPage/DashboardCard.tsx +++ b/dapp/src/pages/DashboardPage/DashboardCard.tsx @@ -15,8 +15,9 @@ import { TextMd } from "#/components/shared/Typography" import IconTag from "#/components/shared/IconTag" import { BoostArrowIcon } from "#/assets/icons" import { CurrencyBalanceWithConversion } from "#/components/shared/CurrencyBalanceWithConversion" -import { AmountType } from "#/types" +import { AmountType, MODAL_TYPES } from "#/types" import { ActivitiesList } from "#/components/shared/ActivitiesList" +import { useModal } from "#/hooks" const buttonStyles: ButtonProps = { size: "lg", @@ -35,6 +36,9 @@ type DashboardCardProps = CardProps & { export default function DashboardCard(props: DashboardCardProps) { const { bitcoinAmount, positionPercentage, ...restProps } = props + + const { openModal } = useModal() + return ( @@ -83,7 +87,12 @@ export default function DashboardCard(props: DashboardCardProps) { - +