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

Add Welcome component #836

Merged
merged 20 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
14 changes: 10 additions & 4 deletions dapp/src/DApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,21 @@ import queryClient from "./queryClient"
import { delay, logPromiseFailure } from "./utils"
import { AcreLogo } from "./assets/icons"

function SplashPage() {
return (
<Center h="100vh" w="100vw">
<Icon as={AcreLogo} w={200} h={300} />
</Center>
)
}

function DApp() {
useInitApp()

return (
<>
<GlobalStyles />
<RouterProvider router={router} />
<RouterProvider router={router} fallbackElement={<SplashPage />} />
<ReactQueryDevtools initialIsOpen={false} />
</>
)
Expand All @@ -48,9 +56,7 @@ function DAppProviders() {
if (!config)
return (
<Fade in={!config}>
<Center h="100vh" w="100vw">
<Icon as={AcreLogo} alt="Acre logo" w={200} h={300} />
</Center>
<SplashPage />
</Fade>
)

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
3 changes: 2 additions & 1 deletion dapp/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react"
import { Outlet } from "react-router-dom"
import { Flex, VStack } from "@chakra-ui/react"
import { useIsEmbed, useMobileMode } from "#/hooks"
import { DappMode } from "#/types"
import DocsDrawer from "./DocsDrawer"
import Header from "./Header"
import ModalRoot from "./ModalRoot"
Expand All @@ -10,7 +11,7 @@ import MobileModeBanner from "./MobileModeBanner"
import Footer from "./Footer"

const PADDING = "2.5rem" // 40px
const PAGE_MAX_WIDTH = {
const PAGE_MAX_WIDTH: Record<DappMode, string> = {
standalone: "63rem", // 1008px
"ledger-live": "63rem", // 1008px
}
Expand Down
26 changes: 0 additions & 26 deletions dapp/src/components/LoadingModal.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions dapp/src/components/ModalRoot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import ConnectWalletModal from "../ConnectWalletModal"
import UnexpectedErrorModal from "../UnexpectedErrorModal"
import AcrePointsClaimModal from "../AcrePointsClaimModal"
import GateModal from "../GateModal"
import LoadingModal from "../LoadingModal"

const MODALS: Record<ModalType, ElementType> = {
STAKE: TransactionModal,
Expand All @@ -19,7 +18,6 @@ const MODALS: Record<ModalType, ElementType> = {
UNEXPECTED_ERROR: UnexpectedErrorModal,
ACRE_POINTS_CLAIM: AcrePointsClaimModal,
GATE: GateModal,
LOADING: LoadingModal,
} as const

export default function ModalRoot() {
Expand Down
244 changes: 177 additions & 67 deletions dapp/src/components/WelcomeModal.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,193 @@
import React from "react"
import React, { ReactElement } from "react"
import {
Button,
ModalBody,
ModalHeader,
VStack,
Image,
Box,
Flex,
ModalCloseButton,
Stepper,
Step,
StepIndicator,
ModalFooter,
useSteps,
SimpleGrid,
StepIndicatorProps,
UseStepsReturn,
Highlight,
} from "@chakra-ui/react"
import { H5, TextLg, TextMd, TextSm } from "#/components/shared/Typography"
import { useModal } from "#/hooks"
import confettiWebp from "#/assets/webps/confetti.webp"
import { BENEFITS } from "#/constants"
import { H3, TextSm } from "#/components/shared/Typography"
import { BaseModalProps, DappMode } from "#/types"
import { EmbedApp } from "#/utils/referralProgram"
import { useIsEmbed } from "#/hooks"
import withBaseModal from "./ModalRoot/withBaseModal"
import step1Video from "../assets/videos/welcome-steps/welcome-step-1.mp4"
import step2Video from "../assets/videos/welcome-steps/welcome-step-2.mp4"
import step3Video from "../assets/videos/welcome-steps/welcome-step-3.mp4"

function WelcomeModalBase() {
const { closeModal } = useModal()
const handleCloseModal = () => {
closeModal()
}
const dappModeToContent: Record<DappMode, () => ReactElement> = {
standalone: () => (
<>
Acre makes earning rewards with your BTC simple and secure. Dedicated to
everyone, it&apos;s fun and easy to use. No advanced knowledge required.
</>
),
"ledger-live": () => (
<Highlight query="Ledger Live">
Acre makes earning rewards with your BTC simple and secure. Tailored for
Ledger Live everyone, it&apos;s fun and easy to use. No advanced knowledge
required.
</Highlight>
),
}

const steps = [
{
id: 0,
title: (
<H3 fontWeight="semibold">
Activate your BTC,{" "}
<Box as="span" display="block" color="orange.30">
earn rewards
</Box>
</H3>
),
content: (embeddedApp?: EmbedApp) =>
dappModeToContent[embeddedApp ?? "standalone"](),

video: step1Video,
},
{
id: 1,
title: (
<H3 fontWeight="semibold">
<Box as="span" display="block" color="orange.30">
Battle-tested{" "}
</Box>
in the market
</H3>
),
content: () => (
<Highlight query="tBTC">
Acre is powered by tBTC, the trusted Bitcoin bridge that secured over
half a billion dollars in BTC. No centralized custodians, everything is
fully on-chain.
</Highlight>
),
video: step2Video,
},
{
id: 2,
title: (
<H3 fontWeight="semibold">
One dashboard{" "}
<Box as="span" display="block" color="orange.30">
endless rewards
</Box>
</H3>
),
content: () => (
<Highlight query="Acre Points Program">
As a depositor, you&apos;re automatically in the Acre Points Program.
Enjoy daily points drops and exclusive partner rewards. Start stacking
those points!
</Highlight>
),
video: step3Video,
},
]

const stepIndicatorStyleProps: StepIndicatorProps = {
sx: {
"[data-status=active] &": {
opacity: 1,
w: "4",
rounded: "6",
_after: {
content: '""',
position: "absolute",
opacity: "0.15",
w: "4",
h: "2.5",
rounded: "5",
left: "1.5",
bgColor: "orange.50",
},
},
"&[data-status=complete], [data-status=incomplete] &": {
bgColor: "orange.50",
},
},
border: "none",
w: "2.5",
h: "2.5",
rounded: "50%",
bgColor: "orange.50",
position: "relative",
opacity: "0.15",
}

function WelcomeModalBase({ closeModal }: BaseModalProps) {
// Cast to fix eslint error: `unbound-method`.
const { activeStep, goToNext } = useSteps({
index: 0,
count: steps.length,
}) as UseStepsReturn & { goToNext: () => void }
const { embeddedApp } = useIsEmbed()
Comment on lines +130 to +134
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably update the Chakra package, see here. But let's leave it as it is for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. But it's not a good time to update main packages just before the release.

Copy link
Member

Choose a reason for hiding this comment

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

Let's add it to our backlog.


const isLastStep = activeStep + 1 === steps.length
const activeStepData = steps[activeStep]

return (
<>
<ModalHeader
display="flex"
flexDirection="column"
alignItems="center"
gap={3}
pb={8}
>
<H5 color="brand.400" fontWeight="semibold">
Welcome to your dashboard!
</H5>
<TextMd color="grey.600">It is time to stack up the rewards!</TextMd>
</ModalHeader>
<ModalBody gap={10}>
<Button size="lg" fontWeight="bold" onClick={handleCloseModal}>
Claim rewards
</Button>
<Flex
gap={4}
justifyContent="center"
alignItems="flex-start"
overflow="visible"
>
{BENEFITS.map(({ name, description, imageSrc }) => (
// 13.25rem -> 212px
<VStack key={name} w="13.25rem">
<Box
w="100%"
h="7.5rem" // 120px
border="1px solid white"
borderRadius="xl"
bgImage={confettiWebp}
bgSize="cover"
bgBlendMode="multiply"
bgColor="gold.200"
display="flex"
alignItems="flex-end"
>
<Image
src={imageSrc}
maxW="7.5rem" // 120px
mx="auto"
/>
</Box>
<TextLg fontWeight="bold" color="grey.700">
{name}
</TextLg>
<TextSm px={1} color="grey.600">
{description}
</TextSm>
</VStack>
))}
</Flex>
</ModalBody>
<ModalCloseButton />
<SimpleGrid columns={2} templateColumns="1fr auto">
<Box>
<ModalHeader gap={3} pb={8}>
<TextSm mb="12" color="neutral.70">
Welcome to Acre,
</TextSm>
{activeStepData.title}
</ModalHeader>
<ModalBody textAlign="left" display="block" color="brown.80" px="10">
{activeStepData.content(embeddedApp)}
</ModalBody>
<ModalFooter
display="flex"
flexDirection="row"
justifyContent="space-between"
mt="14"
>
<Stepper index={activeStep} gap="3">
{steps.map((step) => (
<Step key={step.id}>
<StepIndicator {...stepIndicatorStyleProps} />
</Step>
))}
</Stepper>
<Button
variant={isLastStep ? undefined : "outline"}
onClick={isLastStep ? closeModal : goToNext}
>
{isLastStep ? "Get started" : "Skip"}
</Button>
</ModalFooter>
</Box>
<Box
as="video"
src={activeStepData.video}
width="xs"
height="full"
autoPlay
muted
objectFit="cover"
roundedRight="xl"
/>
</SimpleGrid>
</>
)
}

const WelcomeModal = withBaseModal(WelcomeModalBase, { size: "xl" })
const WelcomeModal = withBaseModal(WelcomeModalBase, {
size: "xl",
})
export default WelcomeModal
9 changes: 7 additions & 2 deletions dapp/src/hooks/useAccessCode.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { useCallback } from "react"
import useLocalStorage from "./useLocalStorage"
import useLocalStorage, { getLocalStorageItem } from "./useLocalStorage"

const LOCAL_STORAGE_KEY = "acre.accessCode"

export function getAccessCodeFromLocalStorage() {
return getLocalStorageItem(LOCAL_STORAGE_KEY)
}
export default function useAccessCode() {
const [encodedCode, setAccessCode] = useLocalStorage<string | undefined>(
"acre.accessCode",
LOCAL_STORAGE_KEY,
undefined,
)

Expand Down
Loading
Loading