Skip to content

Commit

Permalink
Initialization of the staking flow
Browse files Browse the repository at this point in the history
  • Loading branch information
kkosiorowska committed Dec 6, 2023
1 parent 8f4b700 commit d9d70ae
Show file tree
Hide file tree
Showing 18 changed files with 317 additions and 36 deletions.
14 changes: 10 additions & 4 deletions dapp/src/DApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import React from "react"
import { ChakraProvider } from "@chakra-ui/react"
import { useDetectThemeMode } from "./hooks"
import theme from "./theme"
import { LedgerWalletAPIProvider, WalletContextProvider } from "./contexts"
import {
LedgerWalletAPIProvider,
StakingFlowProvider,
WalletContextProvider,
} from "./contexts"
import Header from "./components/Header"
import Overview from "./components/Overview"

Expand All @@ -23,9 +27,11 @@ function DAppProviders() {
return (
<LedgerWalletAPIProvider>
<WalletContextProvider>
<ChakraProvider theme={theme}>
<DApp />
</ChakraProvider>
<StakingFlowProvider>
<ChakraProvider theme={theme}>
<DApp />
</ChakraProvider>
</StakingFlowProvider>
</WalletContextProvider>
</LedgerWalletAPIProvider>
)
Expand Down
4 changes: 3 additions & 1 deletion dapp/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import React from "react"
import { Flex } from "@chakra-ui/react"
import ConnectWallet from "./ConnectWallet"

export const HEADER_HEIGHT = 24

export default function Header() {
return (
<Flex justifyContent="end" p={6}>
<Flex justifyContent="end" p={6} height={HEADER_HEIGHT}>
<ConnectWallet />
</Flex>
)
Expand Down
41 changes: 41 additions & 0 deletions dapp/src/components/ModalOverlay/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useEffect, useState } from "react"
import { Box, useColorModeValue } from "@chakra-ui/react"
import { useStakingFlowContext } from "../../hooks"

const DELAY = 300

export default function ModalOverlay({ marginTop }: { marginTop?: number }) {
const { modalType } = useStakingFlowContext()
const [showOverlay, setShowOverlay] = useState(!modalType)

useEffect(() => {
const timeout = setTimeout(
() => {
setShowOverlay(!!modalType)
},
// When the modal opens, we should show the sidebar without delay.
// However, when the modal disappears, the overlay should disappear with some delay.
modalType ? 0 : DELAY,
)
return () => clearTimeout(timeout)
}, [modalType])

return (
<Box
top={0}
left={0}
w="100vw"
h="100vh"
position="fixed"
// TODO: Set the correct background color
bg={useColorModeValue("grey.100", "grey.300")}
opacity={modalType ? 1 : 0}
zIndex="overlay"
// Hide the element when it is no longer needed.
display={showOverlay ? "block" : "none"}
// zIndex={showOverlay ? "overlay" : "-1"}
transition={`opacity ${DELAY}ms`}
mt={marginTop}
/>
)
}
23 changes: 23 additions & 0 deletions dapp/src/components/Modals/BaseModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react"
import { Modal, ModalCloseButton, ModalContent } from "@chakra-ui/react"
import { useStakingFlowContext } from "../../hooks"
import { HEADER_HEIGHT } from "../Header"

export default function BaseModal({ children }: { children: React.ReactNode }) {
const { closeModal } = useStakingFlowContext()

return (
<Modal isOpen onClose={closeModal} size="md">
<ModalContent p={4} gap={4} mt={2 * HEADER_HEIGHT}>
<ModalCloseButton
top={-8}
right={-8}
border="1px"
borderColor="white"
rounded="100%"
/>
{children}
</ModalContent>
</Modal>
)
}
44 changes: 44 additions & 0 deletions dapp/src/components/Modals/ConnectWalletModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react"
import {
Button,
Image,
ModalBody,
ModalFooter,
ModalHeader,
VStack,
Text,
} from "@chakra-ui/react"
import { useRequestBitcoinAccount } from "../../hooks"
import BaseModal from "./BaseModal"
import ConnectBTCAccount from "../../static/images/ConnectBTCAccount.png"

export default function ConnectWalletModal() {
const { requestAccount } = useRequestBitcoinAccount()

return (
<BaseModal>
<ModalHeader textAlign="center">
Bitcoin account not installed
</ModalHeader>
<ModalBody>
<VStack spacing={12} mt={8}>
<Image src={ConnectBTCAccount} />
<Text textAlign="center">
Bitcoin account is required to make transactions for depositing and
staking your BTC.
</Text>
</VStack>
</ModalBody>
<ModalFooter>
<Button
width="100%"
onClick={async () => {
await requestAccount()
}}
>
Connect wallet
</Button>
</ModalFooter>
</BaseModal>
)
}
67 changes: 67 additions & 0 deletions dapp/src/components/Modals/StakingOverviewModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from "react"
import {
Button,
Flex,
ModalBody,
ModalFooter,
ModalHeader,
Step,
StepDescription,
StepIndicator,
StepNumber,
StepSeparator,
StepTitle,
Stepper,
} from "@chakra-ui/react"
import { useStakingFlowContext } from "../../hooks"
import BaseModal from "./BaseModal"

const STEPS = [
{
title: "Sign message",
description:
"You will sign a gas-free Ethereum message to indicate the address where you'd like to get your stBTC liquid staking token.",
},
{
title: "Deposit BTC",
description:
"You will make a Bitcoin transaction to deposit and stake your BTC.",
},
]

export default function StakingOverviewModal() {
const { closeModal } = useStakingFlowContext()

return (
<BaseModal>
<ModalHeader textAlign="center">Staking overview</ModalHeader>
<ModalBody>
<Stepper
index={2}
gap="0"
height="200px"
orientation="vertical"
variant="basic"
>
{STEPS.map((step) => (
<Step key={step.title}>
<StepIndicator>
<StepNumber />
</StepIndicator>
<Flex direction="column" gap={2}>
<StepTitle>{step.title}</StepTitle>
<StepDescription>{step.description}</StepDescription>
</Flex>
<StepSeparator />
</Step>
))}
</Stepper>
</ModalBody>
<ModalFooter>
<Button width="100%" onClick={closeModal}>
Get started
</Button>
</ModalFooter>
</BaseModal>
)
}
49 changes: 28 additions & 21 deletions dapp/src/components/Overview/PositionDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,41 @@ import {
} from "@chakra-ui/react"
import { BITCOIN, USD } from "../../constants"
import { Info } from "../../static/icons"
import Staking from "../Staking"
import { useStakingFlowContext } from "../../hooks"

export default function PositionDetails() {
const { setModalType } = useStakingFlowContext()

return (
<Flex p={4} h="100%" direction="column" justifyContent="space-between">
<Flex direction="column" gap={2}>
<Text>Your positions</Text>
<Flex direction="column" alignItems="flex-start">
<HStack>
<Text>34.75</Text>
<Text>{BITCOIN.symbol}</Text>
</HStack>
<Flex w="100%" justifyContent="space-between">
<>
<Flex p={4} h="100%" direction="column" justifyContent="space-between">
<Flex direction="column" gap={2}>
<Text>Your positions</Text>
<Flex direction="column" alignItems="flex-start">
<HStack>
<Text>1.245.148,1</Text>
<Text>{USD.symbol}</Text>
<Text>34.75</Text>
<Text>{BITCOIN.symbol}</Text>
</HStack>
{/* TODO: Add correct text for tooltip */}
<Tooltip label="Template">
<Icon as={Info} color={useColorModeValue("black", "grey.80")} />
</Tooltip>
<Flex w="100%" justifyContent="space-between">
<HStack>
<Text>1.245.148,1</Text>
<Text>{USD.symbol}</Text>
</HStack>
{/* TODO: Add correct text for tooltip */}
<Tooltip label="Template">
<Icon as={Info} color={useColorModeValue("black", "grey.80")} />
</Tooltip>
</Flex>
</Flex>
</Flex>
<Flex direction="column" gap={2}>
{/* TODO: Handle click actions */}
<Button onClick={() => setModalType("overview")}>Stake</Button>
<Button variant="outline">Withdraw</Button>
</Flex>
</Flex>
<Flex direction="column" gap={2}>
{/* TODO: Handle click actions */}
<Button>Stake</Button>
<Button variant="outline">Withdraw</Button>
</Flex>
</Flex>
<Staking />
</>
)
}
28 changes: 28 additions & 0 deletions dapp/src/components/Staking/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react"
import ConnectWalletModal from "../Modals/ConnectWalletModal"
import StakingOverviewModal from "../Modals/StakingOverviewModal"
import { useStakingFlowContext, useWalletContext } from "../../hooks"
import ModalOverlay from "../ModalOverlay"
import { HEADER_HEIGHT } from "../Header"

function Modal() {
const { modalType } = useStakingFlowContext()
const { btcAccount } = useWalletContext()

if (!modalType) return null

if (!btcAccount) return <ConnectWalletModal />

if (modalType === "overview") return <StakingOverviewModal />
}

export default function Staking() {
return (
<>
<Modal />
{/* The user has several modals in a flow.
Let's use our own modal overlay to prevent the background flickering effect. */}
<ModalOverlay marginTop={HEADER_HEIGHT} />
</>
)
}
42 changes: 42 additions & 0 deletions dapp/src/contexts/StakingFlowContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { createContext, useCallback, useMemo, useState } from "react"
import { ModalType } from "../types"

type StakingFlowContextValue = {
modalType: ModalType | undefined
closeModal: () => void
setModalType: React.Dispatch<React.SetStateAction<ModalType | undefined>>
}

export const StakingFlowContext = createContext<StakingFlowContextValue>({
modalType: undefined,
setModalType: () => {},
closeModal: () => {},
})

export function StakingFlowProvider({
children,
}: {
children: React.ReactNode
}): React.ReactElement {
const [modalType, setModalType] = useState<ModalType | undefined>(undefined)

const closeModal = useCallback(() => {
setModalType(undefined)
}, [])

const contextValue: StakingFlowContextValue =
useMemo<StakingFlowContextValue>(
() => ({
modalType,
closeModal,
setModalType,
}),
[modalType, closeModal],
)

return (
<StakingFlowContext.Provider value={contextValue}>
{children}
</StakingFlowContext.Provider>
)
}
11 changes: 7 additions & 4 deletions dapp/src/contexts/WalletContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ type WalletContextValue = {
setEthAccount: React.Dispatch<React.SetStateAction<Account | undefined>>
}

export const WalletContext = createContext<WalletContextValue | undefined>(
undefined,
)
export const WalletContext = createContext<WalletContextValue>({
ethAccount: undefined,
btcAccount: undefined,
setEthAccount: () => {},
setBtcAccount: () => {},
})

export function WalletContextProvider({
children,
Expand All @@ -27,7 +30,7 @@ export function WalletContextProvider({
ethAccount,
setEthAccount,
}),
[btcAccount, setBtcAccount, ethAccount, setEthAccount],
[btcAccount, ethAccount],
)

return (
Expand Down
1 change: 1 addition & 0 deletions dapp/src/contexts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./WalletContext"
export * from "./LedgerWalletAPIProvider"
export * from "./StakingFlowContext"
1 change: 1 addition & 0 deletions dapp/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./useDetectThemeMode"
export * from "./useRequestBitcoinAccount"
export * from "./useRequestEthereumAccount"
export * from "./useWalletContext"
export * from "./useStakingFlowContext"
Loading

0 comments on commit d9d70ae

Please sign in to comment.