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

Dashboard: ActivitiesList component #400

Merged
merged 14 commits into from
May 14, 2024
Merged
10 changes: 5 additions & 5 deletions dapp/src/assets/icons/LoadingSpinnerSuccessIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ import { createIcon } from "@chakra-ui/react"

export const LoadingSpinnerSuccessIcon = createIcon({
displayName: "LoadingSpinnerSuccessIcon",
viewBox: "0 0 72 73",
viewBox: "0 0 48 48",
defaultProps: {
fill: "none",
},
path: [
<path
d="M68.625 36.5C68.625 40.7844 67.7811 45.0268 66.1416 48.985C64.502 52.9433 62.0989 56.5398 59.0694 59.5694C56.0398 62.5989 52.4433 65.002 48.485 66.6416C44.5268 68.2811 40.2844 69.125 36 69.125C31.7156 69.125 27.4732 68.2811 23.5149 66.6416C19.5567 65.002 15.9601 62.5989 12.9306 59.5694C9.90112 56.5398 7.49799 52.9433 5.85843 48.985C4.21887 45.0268 3.375 40.7844 3.375 36.5C3.375 32.2156 4.21887 27.9732 5.85843 24.0149C7.498 20.0567 9.90114 16.4601 12.9307 13.4306C15.9602 10.4011 19.5567 7.99798 23.515 6.35842C27.4732 4.71887 31.7156 3.875 36 3.875C40.2844 3.875 44.5268 4.71887 48.4851 6.35844C52.4433 7.998 56.0399 10.4011 59.0694 13.4307C62.0989 16.4602 64.502 20.0567 66.1416 24.015C67.7811 27.9732 68.625 32.2156 68.625 36.5L68.625 36.5Z"
d="M45.75 24C45.75 26.8563 45.1874 29.6845 44.0944 32.3234C43.0013 34.9622 41.3992 37.3599 39.3796 39.3796C37.3599 41.3992 34.9622 43.0013 32.3234 44.0944C29.6845 45.1874 26.8562 45.75 24 45.75C21.1437 45.75 18.3155 45.1874 15.6766 44.0944C13.0378 43.0013 10.6401 41.3992 8.62042 39.3796C6.60075 37.3599 4.99866 34.9622 3.90562 32.3234C2.81258 29.6845 2.25 26.8562 2.25 24C2.25 21.1437 2.81258 18.3155 3.90562 15.6766C4.99866 13.0378 6.60076 10.6401 8.62043 8.62042C10.6401 6.60075 13.0378 4.99866 15.6766 3.90562C18.3155 2.81258 21.1438 2.25 24 2.25C26.8563 2.25 29.6845 2.81258 32.3234 3.90562C34.9622 4.99867 37.3599 6.60076 39.3796 8.62044C41.3993 10.6401 43.0013 13.0378 44.0944 15.6766C45.1874 18.3155 45.75 21.1438 45.75 24L45.75 24Z"
stroke="#EDD8A2"
strokeWidth="3"
strokeLinecap="round"
strokeLinejoin="round"
/>,
<path
d="M46.8031 29.3008L32.4031 43.7008L25.2031 37.1008"
stroke="#79CA52"
strokeWidth="4"
d="M31.2008 19.2002L21.6008 28.8002L16.8008 24.4002"
stroke="#318401"
strokeWidth="3"
strokeLinecap="round"
strokeLinejoin="round"
/>,
Expand Down
53 changes: 53 additions & 0 deletions dapp/src/components/shared/ActivitiesList/ActivitiesList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react"
import { List, ListItem, ListProps } from "@chakra-ui/react"
import { AnimatePresence, Variants, motion } from "framer-motion"
import { useActivitiesNEW as useActivities } from "#/hooks"
import ActivitiesListItem from "./ActivitiesListItem"

const MotionList = motion(List)
const MotionListItem = motion(ListItem)

const listItemVariants: Variants = {
mounted: { opacity: 1, x: 0 },
dismissed: { opacity: 0, x: -48 },
}

function ActivitiesList(props: ListProps) {
const activities = useActivities()

const [dismissedActivities, setDismissedActivities] = React.useState<
string[]
>([])

const handleItemDismiss = (txHash: string) => {
setDismissedActivities((prev) => [...prev, txHash])
}

return (
<MotionList pos="relative" {...props}>
{activities.map((item) => (
<AnimatePresence mode="popLayout">
{!dismissedActivities.includes(item.txHash) && (
<MotionListItem
layout="position"
key={item.txHash}
variants={listItemVariants}
initial={false}
animate="mounted"
exit="dismissed"
pb={2}
_last={{ pb: 0 }}
>
<ActivitiesListItem
{...item}
handleDismiss={() => handleItemDismiss(item.txHash)}
/>
</MotionListItem>
)}
</AnimatePresence>
))}
</MotionList>
)
}

export default ActivitiesList
93 changes: 93 additions & 0 deletions dapp/src/components/shared/ActivitiesList/ActivitiesListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from "react"
import { ArrowUpRight, LoadingSpinnerSuccessIcon } from "#/assets/icons"
import { Activity as ActivityType } from "#/types"
import {
Alert,
AlertDescription,
AlertIcon,
AlertProps,
AlertTitle,
Button,
HStack,
Text,
VStack,
VisuallyHidden,
} from "@chakra-ui/react"
import { CurrencyBalance } from "../CurrencyBalance"
import Spinner from "../Spinner"
import BlockExplorerLink from "../BlockExplorerLink"

type ActivitiesListItemProps = Omit<AlertProps, "status"> &
ActivityType & {
handleDismiss?: () => void
}

function ActivitiesListItem(props: ActivitiesListItemProps) {
const { amount, status, txHash, type, handleDismiss, ...restProps } = props

return (
<Alert as={HStack} variant="process" {...restProps}>
<AlertIcon
color="brand.400"
as={status === "completed" ? LoadingSpinnerSuccessIcon : Spinner}
/>

<VStack flex={1} spacing={0} align="stretch">
<HStack justify="space-between" as={AlertTitle}>
<Text as="span">
{status === "completed"
? `${type === "withdraw" ? "Unstaking" : "Staking"} completed`
: `${type === "withdraw" ? "Unstaking" : "Staking"}...`}
</Text>

<CurrencyBalance amount={amount} currency="bitcoin" />
</HStack>
<HStack justify="space-between" as={AlertDescription}>
{status === "completed" ? (
<Button
variant="link"
fontSize="sm"
lineHeight={5}
onClick={handleDismiss}
>
Ok, dismiss
</Button>
) : (
// TODO: To implement. Estimated activity time is not in scope of MVP.
// eslint-disable-next-line react/jsx-no-useless-fragment
<>
{/* <Text as="span">Est. time remaining</Text>
<Text as="span" fontWeight="bold">
{new Date(estimatedTime).getHours()}h
</Text> */}
</>
)}
</HStack>
</VStack>

{txHash && (
<BlockExplorerLink
id={txHash}
chain="bitcoin"
type="transaction"
display="flex"
my={-4}
ml={6}
mr={-6}
h="auto"
alignSelf="stretch"
borderLeftWidth={1}
borderColor="inherit"
rounded={0}
px={4}
py={5}
>
<ArrowUpRight color="gray.500" boxSize={4} alignSelf="center" />
<VisuallyHidden>View transaction details</VisuallyHidden>
</BlockExplorerLink>
)}
</Alert>
)
}

export default ActivitiesListItem
1 change: 1 addition & 0 deletions dapp/src/components/shared/ActivitiesList/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ActivitiesList } from "./ActivitiesList"
9 changes: 4 additions & 5 deletions dapp/src/components/shared/BlockExplorerLink/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,24 @@ import { Link, LinkProps } from "@chakra-ui/react"
import { createLinkToBlockExplorerForChain } from "#/utils"

type BlockExplorerLinkProps = {
text?: string
id: string
type: ExplorerDataType
chain?: Chain
} & Omit<LinkProps, "isExternal">

function BlockExplorerLink({
text,
id,
type,
chain = "ethereum",
...linkProps
children,
...restProps
}: BlockExplorerLinkProps) {
const { link, title } = createLinkToBlockExplorerForChain(chain, id, type)

// TODO: Update when ButtonLink is ready
return (
<Link href={link} isExternal {...linkProps}>
{text ?? title}
<Link href={link} isExternal {...restProps}>
{children ?? title}
</Link>
)
}
Expand Down
3 changes: 3 additions & 0 deletions dapp/src/pages/DashboardPage/DashboardCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import IconTag from "#/components/shared/IconTag"
import { BoostArrowIcon } from "#/assets/icons"
import { CurrencyBalanceWithConversion } from "#/components/shared/CurrencyBalanceWithConversion"
import { AmountType } from "#/types"
import { ActivitiesList } from "#/components/shared/ActivitiesList"

const buttonStyles: ButtonProps = {
size: "lg",
Expand Down Expand Up @@ -87,6 +88,8 @@ export default function DashboardCard(props: DashboardCardProps) {
Withdraw
</Button>
</HStack>

<ActivitiesList />
</CardBody>
</Card>
)
Expand Down
57 changes: 51 additions & 6 deletions dapp/src/theme/Alert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import {
defineStyle,
} from "@chakra-ui/react"

const baseStyleDialog = defineStyle({
const multiStyleConfig = createMultiStyleConfigHelpers(parts.keys)

// Base styles

const baseContainerStyles = defineStyle({
px: 5,
borderRadius: "xl",
textAlign: "left",
Expand All @@ -15,17 +19,17 @@ const baseStyleDialog = defineStyle({
boxShadow: "0px 8px 12px 0px var(--chakra-colors-opacity-black-15)",
})

const baseStyleIcon = defineStyle({
const baseIconStyles = defineStyle({
mr: 2,
})

const multiStyleConfig = createMultiStyleConfigHelpers(parts.keys)

const baseStyle = multiStyleConfig.definePartsStyle({
container: baseStyleDialog,
icon: baseStyleIcon,
container: baseContainerStyles,
icon: baseIconStyles,
})

// Status styles

const statusInfo = multiStyleConfig.definePartsStyle({
container: {
bg: "blue.500",
Expand Down Expand Up @@ -57,12 +61,53 @@ const statusStyles = (props: StyleFunctionProps) => {
return styleMap[status as string] || {}
}

// Subtle variant styles

const variantSubtle = multiStyleConfig.definePartsStyle((props) =>
statusStyles(props),
)

// Process variant styles

const processContainerStyles = defineStyle({
px: 6,
py: 4,
bg: "gold.300",
borderWidth: 1,
borderColor: "gold.100",
shadow: "none",
alignItems: "flex-start",
})

const processIconStyles = defineStyle({
mr: 4,
w: 12,
h: 12,
})

const processTitleStyles = defineStyle({
color: "grey.700",
fontWeight: "bold",
m: 0,
})

const processDescriptionStyles = defineStyle({
color: "grey.500",
fontWeight: "medium",
})

const processVariant = multiStyleConfig.definePartsStyle({
container: processContainerStyles,
icon: processIconStyles,
title: processTitleStyles,
description: processDescriptionStyles,
})

// Theme definition

const variants = {
subtle: variantSubtle,
process: processVariant,
}

export const alertTheme = multiStyleConfig.defineMultiStyleConfig({
Expand Down
7 changes: 7 additions & 0 deletions dapp/src/theme/Button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,12 @@ export const buttonTheme: ComponentSingleStyleConfig = {
pointerEvents: "none",
},
},
link: {
bg: "initial",
color: "inherit",
p: 0,
textDecoration: "underline",
fontWeight: "medium",
},
},
}
Loading