Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update deposit flow #401

Merged
merged 16 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions dapp/src/assets/icons/ShieldPlus.tsx

This file was deleted.

1 change: 0 additions & 1 deletion dapp/src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export * from "./ArrowRight"
export * from "./AcreLogo"
export * from "./stBTC"
export * from "./BTC"
export * from "./ShieldPlus"
export * from "./Pending"
export * from "./Syncing"
export * from "./Complete"
Expand Down
68 changes: 68 additions & 0 deletions dapp/src/assets/images/rewards-boost-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed dapp/src/assets/images/right-sidebar-bg.png
Binary file not shown.
81 changes: 81 additions & 0 deletions dapp/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from "react"
import {
Box,
Card,
CardBody,
Flex,
useMultiStyleConfig,
Image,
} from "@chakra-ui/react"
import { useSidebar, useDocsDrawer } from "#/hooks"
import rewardsBoostArrow from "#/assets/images/rewards-boost-arrow.svg"
import mysteryBoxIcon from "#/assets/images/mystery-box.svg"
import seasonKeyIcon from "#/assets/images/season-key.svg"
import ButtonLink from "./shared/ButtonLink"
import { TextSm } from "./shared/Typography"

const BUTTONS = [
{ label: "Docs", variant: "solid" },
{ label: "FAQ", colorScheme: "gold" },
{ label: "Token Contract", colorScheme: "gold" },
{ label: "Bridge Contract", colorScheme: "gold" },
]

const BENEFITS = [
{ label: "1x Rewards Boost", iconSrc: rewardsBoostArrow },
{ label: "1x Mystery Box", iconSrc: mysteryBoxIcon },
{ label: "1x Season Key", iconSrc: seasonKeyIcon },
]

export default function Sidebar() {
const { isOpen } = useSidebar()
const { onOpen: openDocsDrawer } = useDocsDrawer()
const styles = useMultiStyleConfig("Sidebar")

return (
<Box
as="aside"
mt="header_height"
w={isOpen ? "sidebar_width" : "0"}
__css={styles.sidebarContainer}
>
<Box __css={styles.sidebar}>
<TextSm fontWeight="bold">Rewards you’ll unlock</TextSm>

<Flex mt={2} mb={7} flexDir="column" gap={2}>
{BENEFITS.map(({ label, iconSrc }) => (
<Card
key={label}
bg="gold.300"
borderWidth="1px"
borderColor="white"
>
<CardBody
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
py={0}
px={4}
>
<TextSm fontWeight="semibold">{label}</TextSm>
<Image src={iconSrc} boxSize="3.75rem" />
</CardBody>
</Card>
))}
</Flex>

{BUTTONS.map(({ label, variant, colorScheme }) => (
<ButtonLink
key={label}
onClick={openDocsDrawer}
variant={variant}
colorScheme={colorScheme}
>
{label}
</ButtonLink>
))}
</Box>
</Box>
)
}
84 changes: 0 additions & 84 deletions dapp/src/components/Sidebar/index.tsx

This file was deleted.

68 changes: 28 additions & 40 deletions dapp/src/components/TransactionModal/ActionFormModal.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import React, { useCallback, useState } from "react"
import { Box, ModalBody, ModalCloseButton, ModalHeader } from "@chakra-ui/react"
import {
ModalBody,
Tabs,
TabList,
Tab,
TabPanels,
TabPanel,
ModalCloseButton,
} from "@chakra-ui/react"
import {
useModalFlowContext,
useStakeFlowContext,
useTransactionContext,
useWalletContext,
Expand All @@ -20,16 +11,36 @@ import { logPromiseFailure } from "#/utils"
import StakeFormModal from "./ActiveStakingStep/StakeFormModal"
import UnstakeFormModal from "./ActiveUnstakingStep/UnstakeFormModal"

const TABS = Object.values(ACTION_FLOW_TYPES)
const FORM_DATA: Record<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rename "header" to "heading". By header we usually mean the very top component on a page. It's a little confusing
Also we don't need such strict type safety for formComponent. It's declared only once for private use of the component only. Just React.ReactNode is enough.,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rename "header" to "heading". By header we usually mean the very top component on a page. It's a little confusing

Sure, let's change it. 0a420d1

Also we don't need such strict type safety for formComponent. It's declared only once for private use of the component only. Just React.ReactNode is enough.,

We call the content in the component and need to pass the necessary props. Therefore, we need to declare it in such a way as to pass the right props to the component. So even though this is called once I think we need to declare the type here. As a result, when calling renderComponent, we get a suggestion of what props should be given.

Screenshot 2024-05-14 at 08 30 45

Screenshot 2024-05-14 at 08 31 26

However, I have simplified the definition of form component type. - a14030f

ActionFlowType,
{
header: string
FormComponent: (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep the key in camel case. It's confusing.
To use it in JSX you can always rename it while destructuring.

const { foo: Foo } = bar

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm this was a special trick to make it clear that it should be used as a component. However, if there is any doubt I can simplify it.

0a420d1

props: React.ComponentProps<
typeof StakeFormModal | typeof UnstakeFormModal
>,
) => React.ReactNode
}
> = {
stake: {
header: "Deposit",
FormComponent: StakeFormModal,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

},
unstake: {
header: "Withdraw",
FormComponent: UnstakeFormModal,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

},
}

function ActionFormModal({ defaultType }: { defaultType: ActionFlowType }) {
function ActionFormModal({ type }: { type: ActionFlowType }) {
const { btcAccount, ethAccount } = useWalletContext()
const { type, setType } = useModalFlowContext()
const { setTokenAmount } = useTransactionContext()
const { initStake } = useStakeFlowContext()

const [isLoading, setIsLoading] = useState(false)

const { header, FormComponent } = FORM_DATA[type]

const handleInitStake = useCallback(async () => {
const btcAddress = btcAccount?.address
const ethAddress = ethAccount?.address
Expand Down Expand Up @@ -67,34 +78,11 @@ function ActionFormModal({ defaultType }: { defaultType: ActionFlowType }) {
return (
<>
{!isLoading && <ModalCloseButton />}
<ModalHeader>{header}</ModalHeader>
<ModalBody>
<Tabs
w="100%"
variant="underline"
defaultIndex={TABS.indexOf(defaultType)}
>
<TabList pb={6}>
{TABS.map((actionFlowType) => (
<Tab
key={actionFlowType}
w="50%"
pb={4}
onClick={() => setType(actionFlowType)}
isDisabled={actionFlowType !== type && isLoading}
>
{actionFlowType}
</Tab>
))}
</TabList>
<TabPanels>
<TabPanel>
<StakeFormModal onSubmitForm={handleSubmitFormWrapper} />
</TabPanel>
<TabPanel>
<UnstakeFormModal onSubmitForm={handleSubmitFormWrapper} />
</TabPanel>
</TabPanels>
</Tabs>
<Box w="100%">
<FormComponent onSubmitForm={handleSubmitFormWrapper} />
</Box>
</ModalBody>
</>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from "react"
import React, { useCallback } from "react"
import {
useDepositBTCTransaction,
useDepositTelemetry,
Expand All @@ -9,13 +9,16 @@ import {
useTransactionContext,
useWalletContext,
} from "#/hooks"
import { TextMd } from "#/components/shared/Typography"
import { logPromiseFailure } from "#/utils"
import { PROCESS_STATUSES } from "#/types"
import { CardAlert } from "#/components/shared/alerts"
import { TOASTS, TOAST_IDS } from "#/types/toast"
import StakingStepsModalContent from "./StakingStepsModalContent"
import { ModalBody, ModalHeader, Highlight, useTimeout } from "@chakra-ui/react"
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"

const DELAY = ONE_SEC_IN_MILLISECONDS * 2
const TOAST_ID = TOAST_IDS.DEPOSIT_TRANSACTION_ERROR
const TOAST = TOASTS[TOAST_ID]

Expand All @@ -27,9 +30,6 @@ export default function DepositBTCModal() {
const depositTelemetry = useDepositTelemetry()
const { closeToast, openToast } = useToast()

const [isLoading, setIsLoading] = useState(false)
const [buttonText, setButtonText] = useState("Deposit BTC")

const onStakeBTCSuccess = useCallback(
() => setStatus(PROCESS_STATUSES.SUCCEEDED),
[setStatus],
Expand Down Expand Up @@ -57,7 +57,6 @@ export default function DepositBTCModal() {
id: TOAST_ID,
render: TOAST,
})
setButtonText("Try again")
}, [openToast])

const onDepositBTCError = useCallback(() => showError(), [showError])
Expand All @@ -71,13 +70,11 @@ export default function DepositBTCModal() {
if (!tokenAmount?.amount || !btcAddress || !depositReceipt || !ethAccount)
return

setIsLoading(true)
const response = await depositTelemetry(
depositReceipt,
btcAddress,
ethAccount.address,
)
setIsLoading(false)

if (response.verificationStatus === "valid") {
logPromiseFailure(sendBitcoinTransaction(tokenAmount?.amount, btcAddress))
Expand All @@ -98,18 +95,23 @@ export default function DepositBTCModal() {
logPromiseFailure(handledDepositBTC())
}, [handledDepositBTC])

useTimeout(handledDepositBTCWrapper, DELAY)

return (
<StakingStepsModalContent
buttonText={buttonText}
activeStep={1}
isLoading={isLoading}
onClick={handledDepositBTCWrapper}
>
<CardAlert status="error">
<TextMd>
Make a Bitcoin transaction to deposit and stake your BTC.
</TextMd>
</CardAlert>
</StakingStepsModalContent>
<>
<ModalHeader>Waiting transaction...</ModalHeader>
<ModalBody>
<Spinner size="xl" />
<TextMd>Please complete the transaction in your wallet.</TextMd>
<CardAlert>
<TextMd>
<Highlight query="Rewards" styles={{ fontWeight: "bold" }}>
You will receive your Rewards once the deposit transaction is
completed.
</Highlight>
</TextMd>
</CardAlert>
</ModalBody>
</>
)
}
Loading
Loading