diff --git a/dapp/src/assets/icons/LoadingSpinnerSuccessIcon.tsx b/dapp/src/assets/icons/LoadingSpinnerSuccessIcon.tsx
index 78abf496b..a4501cb14 100644
--- a/dapp/src/assets/icons/LoadingSpinnerSuccessIcon.tsx
+++ b/dapp/src/assets/icons/LoadingSpinnerSuccessIcon.tsx
@@ -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: [
,
,
diff --git a/dapp/src/components/shared/ActivitiesList/ActivitiesList.tsx b/dapp/src/components/shared/ActivitiesList/ActivitiesList.tsx
new file mode 100644
index 000000000..d4df818ed
--- /dev/null
+++ b/dapp/src/components/shared/ActivitiesList/ActivitiesList.tsx
@@ -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 (
+
+ {activities.map((item) => (
+
+ {!dismissedActivities.includes(item.txHash) && (
+
+ handleItemDismiss(item.txHash)}
+ />
+
+ )}
+
+ ))}
+
+ )
+}
+
+export default ActivitiesList
diff --git a/dapp/src/components/shared/ActivitiesList/ActivitiesListItem.tsx b/dapp/src/components/shared/ActivitiesList/ActivitiesListItem.tsx
new file mode 100644
index 000000000..73403a4ed
--- /dev/null
+++ b/dapp/src/components/shared/ActivitiesList/ActivitiesListItem.tsx
@@ -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 &
+ ActivityType & {
+ handleDismiss?: () => void
+ }
+
+function ActivitiesListItem(props: ActivitiesListItemProps) {
+ const { amount, status, txHash, type, handleDismiss, ...restProps } = props
+
+ return (
+
+
+
+
+
+
+ {status === "completed"
+ ? `${type === "withdraw" ? "Unstaking" : "Staking"} completed`
+ : `${type === "withdraw" ? "Unstaking" : "Staking"}...`}
+
+
+
+
+
+ {status === "completed" ? (
+
+ ) : (
+ // TODO: To implement. Estimated activity time is not in scope of MVP.
+ // eslint-disable-next-line react/jsx-no-useless-fragment
+ <>
+ {/* Est. time remaining
+
+ {new Date(estimatedTime).getHours()}h
+ */}
+ >
+ )}
+
+
+
+ {txHash && (
+
+
+ View transaction details
+
+ )}
+
+ )
+}
+
+export default ActivitiesListItem
diff --git a/dapp/src/components/shared/ActivitiesList/index.ts b/dapp/src/components/shared/ActivitiesList/index.ts
new file mode 100644
index 000000000..30619d084
--- /dev/null
+++ b/dapp/src/components/shared/ActivitiesList/index.ts
@@ -0,0 +1 @@
+export { default as ActivitiesList } from "./ActivitiesList"
diff --git a/dapp/src/components/shared/BlockExplorerLink/index.tsx b/dapp/src/components/shared/BlockExplorerLink/index.tsx
index 82b65d503..f97f61435 100644
--- a/dapp/src/components/shared/BlockExplorerLink/index.tsx
+++ b/dapp/src/components/shared/BlockExplorerLink/index.tsx
@@ -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
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 (
-
- {text ?? title}
+
+ {children ?? title}
)
}
diff --git a/dapp/src/pages/DashboardPage/DashboardCard.tsx b/dapp/src/pages/DashboardPage/DashboardCard.tsx
index 53bd4b16d..5b97bd116 100644
--- a/dapp/src/pages/DashboardPage/DashboardCard.tsx
+++ b/dapp/src/pages/DashboardPage/DashboardCard.tsx
@@ -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",
@@ -87,6 +88,8 @@ export default function DashboardCard(props: DashboardCardProps) {
Withdraw
+
+
)
diff --git a/dapp/src/theme/Alert.ts b/dapp/src/theme/Alert.ts
index cb002ea56..f5dd4b392 100644
--- a/dapp/src/theme/Alert.ts
+++ b/dapp/src/theme/Alert.ts
@@ -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",
@@ -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",
@@ -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({
diff --git a/dapp/src/theme/Button.ts b/dapp/src/theme/Button.ts
index 5b221fb44..94a299791 100644
--- a/dapp/src/theme/Button.ts
+++ b/dapp/src/theme/Button.ts
@@ -133,5 +133,12 @@ export const buttonTheme: ComponentSingleStyleConfig = {
pointerEvents: "none",
},
},
+ link: {
+ bg: "initial",
+ color: "inherit",
+ p: 0,
+ textDecoration: "underline",
+ fontWeight: "medium",
+ },
},
}