Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into sentry-source-maps
Browse files Browse the repository at this point in the history
  • Loading branch information
nkuba committed Oct 21, 2024
2 parents 6d1202b + b901071 commit 8b5d877
Show file tree
Hide file tree
Showing 39 changed files with 1,338 additions and 135 deletions.
3 changes: 2 additions & 1 deletion dapp/.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ VITE_SENTRY_DSN=""
VITE_ETH_HOSTNAME_HTTP="https://sepolia.infura.io/v3/c80e8ccdcc4c4a809bce4fc165310617"
VITE_REFERRAL=0

# TODO: Set this env variable in CI.
# ENDPOINTS
VITE_TBTC_API_ENDPOINT=""
VITE_ACRE_API_ENDPOINT="http://localhost:8788/api/v1/"

Expand All @@ -26,5 +26,6 @@ VITE_FEATURE_FLAG_WITHDRAWALS_ENABLED="false"
VITE_FEATURE_FLAG_OKX_WALLET_ENABLED="false"
VITE_FEATURE_FLAG_XVERSE_WALLET_ENABLED="false"
VITE_FEATURE_FLAG_BEEHIVE_COMPONENT_ENABLED="false"
VITE_FEATURE_FLAG_ACRE_POINTS_ENABLED="true"
VITE_FEATURE_FLAG_TVL_ENABLED="false"

1 change: 1 addition & 0 deletions dapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"formik": "^2.4.5",
"framer-motion": "^10.16.5",
"react": "^18.2.0",
"react-confetti-explosion": "^2.1.2",
"react-dom": "^18.2.0",
"react-number-format": "^5.3.1",
"react-redux": "^9.1.0",
Expand Down
214 changes: 214 additions & 0 deletions dapp/src/components/AcrePointsClaimModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import React, { ReactNode, useEffect, useMemo, useState } from "react"
import { useTimeout } from "#/hooks"
import { Box, Button, ModalBody, VStack } from "@chakra-ui/react"
import {
AnimationSequence,
motion,
Transition,
useAnimate,
} from "framer-motion"
import { logPromiseFailure, numberToLocaleString } from "#/utils"
import { ONE_SEC_IN_MILLISECONDS } from "#/constants"
import ConfettiExplosion from "react-confetti-explosion"
import { BaseModalProps } from "#/types"
import { AnimatedNumber } from "./shared/AnimatedNumber"
import { TextXl } from "./shared/Typography"
import withBaseModal from "./ModalRoot/withBaseModal"

const MotionBox = motion(Box)

const INITIAL_CONTAINER_HEIGHT = 214
const CONTAINER_HEIGHT = 288
const VALUE_SCALE = 0.375
const STEP_HEIGHT = CONTAINER_HEIGHT * (1 - VALUE_SCALE)
const STEP_SPACING = 32
const TRANSITION: Transition = {
type: "spring",
damping: 14,
stiffness: 86,
delay: 4, // step duration
}
const AUTOCLOSE_DELAY = 12 * ONE_SEC_IN_MILLISECONDS
const CONFETTI_DURATION = 4 * ONE_SEC_IN_MILLISECONDS

const getStepOffsets = (
stepCount: number,
stepHeight: number,
spacing: number,
) =>
Array(stepCount - 1)
.fill(0)
.map((_, index) =>
index === 0
? -stepHeight
: (index + 1) * -stepHeight - spacing * 2 ** index,
)

type AcrePointsClaimModalBaseProps = {
claimedAmount: number
totalAmount: number
} & BaseModalProps

function AcrePointsClaimModalBase({
claimedAmount,
totalAmount,
closeModal,
}: AcrePointsClaimModalBaseProps) {
const formattedClaimedAmount = numberToLocaleString(claimedAmount)
const formattedTotalAmount = numberToLocaleString(totalAmount)

const steps = useMemo<[string, ReactNode][]>(
() => [
[
"You earned",
<AnimatedNumber
value={formattedClaimedAmount}
prefix="+"
suffix=" PTS"
animateMode="whileInView"
color="brand.400"
/>,
],
[
"Updating points balance...",
<AnimatedNumber
value={formattedTotalAmount}
suffix=" PTS"
animateMode="whileInView"
indicationColor="brand.400"
/>,
],
// TODO: Uncomment when the leaderboard feature is ready
// [
// "Calculating rank...",
// <AnimatedNumber
// value={rankPositionDifference}
// prefix={rankPositionDifference > 0 ? "+" : "-"}
// animateMode="whileInView"
// color={rankPositionDifference > 0 ? "green.500" : "red.500"}
// />,
// ],
// [
// "Updating rank...",
// <AnimatedNumber
// value={estimatedRankPosition}
// prefix="#"
// animateMode="whileInView"
// indicationColor="brand.400"
// />,
// ],
],
[formattedClaimedAmount, formattedTotalAmount],
)

const [scope, animate] = useAnimate()

useEffect(() => {
const offsets = getStepOffsets(steps.length, STEP_HEIGHT, STEP_SPACING)
const valueElements = [
...(scope.current as HTMLElement).querySelectorAll("[data-step-value]"),
].slice(0, -1)

const sequence = [
["[data-steps-list]", { y: offsets[0] }, TRANSITION],
[
"[data-container]",
{
clipPath: `polygon(0 0, 100% 0, 100% ${CONTAINER_HEIGHT}px, 0 ${CONTAINER_HEIGHT}px)`,
},
{ at: "<", ...TRANSITION },
],

[valueElements[0], { scale: VALUE_SCALE }, { at: "<", ...TRANSITION }],
["[data-close-button]", { opacity: 1 }, { at: "<", ...TRANSITION }],

// TODO: Uncomment when the leaderboard feature is ready

// ["[data-steps-list]", { y: offsets[1] }, TRANSITION],
// [valueElements[1], { scale: VALUE_SCALE }, { at: "<", ...TRANSITION }],

// ["[data-steps-list]", { y: offsets[2] }, TRANSITION],
// [valueElements[2], { scale: VALUE_SCALE }, { at: "<", ...TRANSITION }],
] as AnimationSequence

const handleAnimation = async () => {
await animate(sequence)
}

logPromiseFailure(handleAnimation())
}, [scope, animate, steps])

const [isCofettiExploded, setIsCofettiExploded] = useState(false)

useTimeout(closeModal, AUTOCLOSE_DELAY)

return (
<ModalBody gap={0} p={0} pos="relative" ref={scope}>
<MotionBox
data-container
clipPath={`polygon(0 0, 100% 0, 100% ${INITIAL_CONTAINER_HEIGHT}px, 0 ${INITIAL_CONTAINER_HEIGHT}px)`}
overflow="hidden"
>
<VStack data-steps-list spacing={8}>
{steps.map(([currentStepLabel, currentStepValue]) => (
<Box key={currentStepLabel}>
<TextXl
fontWeight="semibold"
mb="5.25rem" // 84px
>
{currentStepLabel}
</TextXl>

<Box
data-step-value
transformOrigin="bottom"
fontSize="8xl"
lineHeight="6.25rem" // 100px
fontWeight="bold"
color="grey.700"
>
{currentStepValue}
</Box>
</Box>
))}
</VStack>
</MotionBox>

<Button
opacity={0}
onClick={closeModal}
data-close-button
variant="outline"
>
Yay!
</Button>

{!isCofettiExploded && (
<Box
pos="absolute"
top={0}
left="50%"
translateX="-50%"
transform="auto"
>
<ConfettiExplosion
zIndex={1410} // Chakra's modal has a z-index of 1400
width={768}
height="100vh"
duration={CONFETTI_DURATION}
force={0.2}
onComplete={() => setIsCofettiExploded(true)}
/>
</Box>
)}
</ModalBody>
)
}

const AcrePointsClaimModal = withBaseModal(AcrePointsClaimModalBase, {
returnFocusOnClose: false,
variant: "unstyled",
size: "full",
})

export default AcrePointsClaimModal
4 changes: 1 addition & 3 deletions dapp/src/components/MezoBeehiveModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ function MezoBeehiveModalBase() {
<VStack spacing={1}>
{data && (
<HStack>
<H6 fontWeight="bold">
{numberToLocaleString(data.totalMats, 0)}
</H6>
<H6 fontWeight="bold">{numberToLocaleString(data.totalMats)}</H6>
<TextLg fontWeight="bold">MATS</TextLg>
</HStack>
)}
Expand Down
2 changes: 2 additions & 0 deletions dapp/src/components/ModalRoot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import WelcomeModal from "../WelcomeModal"
import MezoBeehiveModal from "../MezoBeehiveModal"
import ConnectWalletModal from "../ConnectWalletModal"
import UnexpectedErrorModal from "../UnexpectedErrorModal"
import AcrePointsClaimModal from "../AcrePointsClaimModal"

const MODALS: Record<ModalType, ElementType> = {
STAKE: TransactionModal,
Expand All @@ -14,6 +15,7 @@ const MODALS: Record<ModalType, ElementType> = {
MEZO_BEEHIVE: MezoBeehiveModal,
CONNECT_WALLET: ConnectWalletModal,
UNEXPECTED_ERROR: UnexpectedErrorModal,
ACRE_POINTS_CLAIM: AcrePointsClaimModal,
} as const

export default function ModalRoot() {
Expand Down
1 change: 0 additions & 1 deletion dapp/src/components/ModalRoot/withBaseModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ function withBaseModal<T extends BaseModalProps>(
<Modal
isOpen
onClose={handleCloseModal}
scrollBehavior="inside"
closeOnOverlayClick={false}
size={MODAL_BASE_SIZE}
closeOnEsc={closeOnEsc}
Expand Down
17 changes: 13 additions & 4 deletions dapp/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ComponentProps } from "react"
import React, { ComponentProps, useEffect } from "react"
import {
Box,
Card,
Expand All @@ -7,7 +7,7 @@ import {
useMultiStyleConfig,
Image,
} from "@chakra-ui/react"
import { useSidebar } from "#/hooks"
import { useScrollbarVisibility, useSidebar } from "#/hooks"
import {
EXTERNAL_HREF,
REWARD_BOOST,
Expand All @@ -18,6 +18,8 @@ import { rewardsBoostArrowImage } from "#/assets/images/benefits"
import ButtonLink from "./shared/ButtonLink"
import { TextSm } from "./shared/Typography"

const CHAKRA_MODAL_CONTAINER_SELECTOR = ".chakra-modal__content-container"

const BUTTONS: Partial<ComponentProps<typeof ButtonLink>>[] = [
{
children: "Docs",
Expand Down Expand Up @@ -52,16 +54,23 @@ const BENEFITS = [

export default function Sidebar() {
const { isOpen } = useSidebar()
// TODO Bring back when dApp embedded docs are ready
// const { onOpen: openDocsDrawer } = useDocsDrawer()
const { isVisible, scrollbarWidth, refreshState } = useScrollbarVisibility(
CHAKRA_MODAL_CONTAINER_SELECTOR,
)
const styles = useMultiStyleConfig("Sidebar")

useEffect(() => {
if (!isOpen) return
refreshState()
}, [isOpen, refreshState])

return (
<Box
as="aside"
mt="header_height"
w={isOpen ? "sidebar_width" : "0"}
__css={styles.sidebarContainer}
mr={isVisible ? scrollbarWidth : 0}
>
<Box __css={styles.sidebar}>
{featureFlags.GAMIFICATION_ENABLED && (
Expand Down
Loading

0 comments on commit 8b5d877

Please sign in to comment.