Skip to content

Commit

Permalink
Activities bar - added carousel
Browse files Browse the repository at this point in the history
  • Loading branch information
ioay committed Mar 4, 2024
1 parent 50de6e7 commit e174e27
Show file tree
Hide file tree
Showing 22 changed files with 551 additions and 178 deletions.
3 changes: 2 additions & 1 deletion dapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@
"@sentry/react": "^7.98.0",
"@sentry/types": "^7.102.0",
"@tanstack/react-table": "^8.11.3",
"@types/react-slick": "^0.23.13",
"axios": "^1.6.7",
"ethers": "^6.10.0",
"axios": "^1.6.7",
"formik": "^2.4.5",
"framer-motion": "^10.16.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-number-format": "^5.3.1",
"react-router-dom": "^6.22.0",
"react-slick": "^0.30.2",
"recharts": "^2.12.0"
},
"devDependencies": {
Expand Down
Empty file.
5 changes: 5 additions & 0 deletions dapp/src/components/GlobalStyles/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ export default function GlobalStyles() {
font-weight: 900;
font-style: normal;
}
// We need to add this style, because of using chakra-ui & react-slick package.
// react-slick doesn't generate flex display style for auto-generated slick-track wrapper.
.slick-track {
display: flex;
}
`}
/>
)
Expand Down
27 changes: 27 additions & 0 deletions dapp/src/components/shared/Activities/ActivityBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useCallback, useState } from "react"
import { Flex } from "@chakra-ui/react"
import { ActivityCard } from "./ActivityCard"
import { mockedActivities } from "./mock-activities"

export function ActivityBar() {
// TODO: Lines 8-18 should be replaced by redux store when subgraphs are implemented
const [activities, setActivities] = useState(mockedActivities)

const onRemove = useCallback(
(activityHash: string) => {
const filteredActivities = activities.filter(
(activity) => activity.txHash !== activityHash,
)
setActivities(filteredActivities)
},
[activities],
)

return (
<Flex gap={3} flexDirection="column">
{activities.map((activity) => (
<ActivityCard activity={activity} onRemove={onRemove} />
))}
</Flex>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, { useCallback } from "react"
import {
CardBody,
CardFooter,
CardHeader,
CardProps,
HStack,
Icon,
Tooltip,
CloseButton,
} from "@chakra-ui/react"
import { useLocation } from "react-router-dom"
import { ActivityInfo, LocationState } from "#/types"
import { capitalize } from "#/utils"
import { ChevronRightIcon } from "#/assets/icons"
import { CurrencyBalance } from "#/components/shared/CurrencyBalance"
import StatusInfo from "#/components/shared/StatusInfo"
import { TextSm } from "#/components/shared/Typography"
import { ActivityCardContainer } from "./ActivityCardContainer"
import { ActivityCardLink } from "./ActivityCardLink"

type ActivityCardType = CardProps & {
activity: ActivityInfo
onRemove: (txHash: string) => void
}

export function ActivityCard({
activity,
onRemove,
...props
}: ActivityCardType) {
const state = useLocation().state as LocationState | null
const isActive = state ? activity.txHash === state.activity.txHash : false
const isCompleted = activity.status === "completed"

const onClose = useCallback(
(event: React.MouseEvent) => {
event.preventDefault()
if (activity.txHash) {
onRemove(activity.txHash)
}
},
[onRemove, activity.txHash],
)

return (
<ActivityCardLink activity={activity} {...props}>
<ActivityCardContainer isCompleted={isCompleted} isActive={isActive}>
<CardHeader p={0} w="100%">
<HStack justifyContent="space-between">
<CurrencyBalance
currency={activity.currency}
amount={activity.amount}
size="xl"
balanceFontWeight="black"
symbolFontWeight="medium"
/>
{isCompleted ? (
<Tooltip label="Remove" placement="top" paddingX={3} paddingY={2}>
<CloseButton
size="sm"
onClick={onClose}
_hover={{ backgroundColor: undefined }}
/>
</Tooltip>
) : (
<Icon
as={ChevronRightIcon}
boxSize={5}
color={isActive ? "gold.700" : "grey.400"}
_hover={isActive ? { color: "gold.700" } : undefined}
/>
)}
</HStack>
</CardHeader>
<CardBody p={0}>
<TextSm fontWeight="semibold" marginBottom={4}>
{capitalize(activity.action)}
</TextSm>
</CardBody>
<CardFooter p={0}>
<StatusInfo
status={activity.status}
withIcon
withDefaultColor
fontWeight="medium"
/>
</CardFooter>
</ActivityCardContainer>
</ActivityCardLink>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const activeStyles = {
},
}

function ActivityCardContainer({
export function ActivityCardContainer({
isActive,
isCompleted,
children,
Expand All @@ -60,5 +60,3 @@ function ActivityCardContainer({
</Card>
)
}

export default ActivityCardContainer
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react"

import { Link as ReactRouterLink } from "react-router-dom"
import { Link as ChakraLink } from "@chakra-ui/react"
import { ActivityInfo } from "#/types"

type ActivityCardLinkProps = {
activity: ActivityInfo
children: React.ReactNode
}

export function ActivityCardLink({
activity,
children,
...props
}: ActivityCardLinkProps) {
return (
<ChakraLink
as={ReactRouterLink}
to="/activity-details"
state={{ activity }}
key={activity.txHash}
{...props}
>
{children}
</ChakraLink>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./ActivityCard"
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useCallback, useRef, useState } from "react"
import Slider from "react-slick"
import { Box, HStack, BoxProps } from "@chakra-ui/react"
import { ActivityCard } from "../ActivityCard"
import { activityCarouselSettings } from "./utils"
import { mockedActivities } from "../mock-activities"

export function ActivityCarousel({ ...props }: BoxProps) {
const sliderRef = useRef<HTMLDivElement & Slider>(null)

// TODO: Lines 12-30 should be replaced by redux store when subgraphs are implemented
const [activities, setActivities] = useState(mockedActivities)

const onRemove = useCallback(
(activityHash: string) => {
const removedIndex = activities.findIndex(
(activity) => activity.txHash === activityHash,
)
const filteredActivities = activities.filter(
(activity) => activity.txHash !== activityHash,
)
const isLastCard = removedIndex === activities.length - 1
if (isLastCard) {
sliderRef.current?.slickPrev()
}
sliderRef.current?.forceUpdate()
setActivities(filteredActivities)
},
[activities],
)

return (
<Box pos="relative" {...props}>
<HStack
as={Slider}
overflow="hidden"
ref={sliderRef}
pl={2}
ml={-2}
overflowX="hidden"
pb={6}
_after={{
content: '""',
pos: "absolute",
right: 0,
w: 20,
height: 40,
bgGradient: "linear(to-r, transparent, gold.300)",
}}
{...activityCarouselSettings}
>
{activities.map((activity) => (
<ActivityCard activity={activity} onRemove={onRemove} mr={3} />
))}
</HStack>
</Box>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./ActivityCarousel"
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react"
import { CustomArrowProps } from "react-slick"
import { Box, IconButton, IconButtonProps } from "@chakra-ui/react"
import { ArrowLeft, ArrowRight } from "#/assets/icons"

type PaginationArrowType = CustomArrowProps & IconButtonProps

function PaginationArrow({ icon, onClick, ...props }: PaginationArrowType) {
return (
<IconButton
icon={icon}
variant="pagination"
size="sm"
borderRadius={32}
onClick={onClick}
isDisabled={onClick === null}
{...props}
/>
)
}

export function PrevArrowCarousel({ onClick }: CustomArrowProps) {
return (
<Box position="absolute" pr={2} right={-56} top={-10}>
<PaginationArrow
onClick={onClick}
icon={<ArrowLeft />}
aria-label="prev"
/>
</Box>
)
}
export function NextArrowCarousel({ onClick }: CustomArrowProps) {
return (
<Box position="absolute" right={-64} top={-10}>
<PaginationArrow
onClick={onClick}
icon={<ArrowRight />}
aria-label="next"
/>
</Box>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from "react"
import { NextArrowCarousel, PrevArrowCarousel } from "./carouselArrows"

/* *
* Settings for react-slick carousel.
* Breakpoints are calculated based on with & visibility of activity card.
* slidesToShow attr is needed to correctly display the number of cards in the carousel
* and it depends on the width of the viewport.
* */
export const activityCarouselSettings = {
dots: false,
infinite: false,
speed: 500,
slidesToShow: 4,
slidesToScroll: 1,
variableWidth: true,
nextArrow: <NextArrowCarousel />,
prevArrow: <PrevArrowCarousel />,
responsive: [
{
breakpoint: 820,
settings: {
slidesToShow: 1,
},
},
{
breakpoint: 1080,
settings: {
slidesToShow: 2,
},
},
{
breakpoint: 1360,
settings: {
slidesToShow: 3,
},
},
{
breakpoint: 1620,
settings: {
slidesToShow: 4,
},
},
{
breakpoint: 1900,
settings: {
slidesToShow: 5,
},
},
{
breakpoint: 2160,
settings: {
slidesToShow: 6,
},
},
{
breakpoint: 2440,
settings: {
slidesToShow: 7,
},
},
{
breakpoint: 2700,
settings: {
slidesToShow: 8,
},
},
{
breakpoint: 2980,
settings: {
slidesToShow: 9,
},
},
{
breakpoint: 3240,
settings: {
slidesToShow: 10,
},
},
],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./carouselArrows"
export * from "./carouselSettings"
2 changes: 2 additions & 0 deletions dapp/src/components/shared/Activities/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./ActivityBar"
export * from "./ActivityCarousel"
Loading

0 comments on commit e174e27

Please sign in to comment.