Skip to content

Commit

Permalink
Release 2.2.0 (#190)
Browse files Browse the repository at this point in the history
  • Loading branch information
schmanu authored Jun 25, 2024
2 parents 2d8a8b7 + fbb398b commit ca3cb78
Show file tree
Hide file tree
Showing 9 changed files with 334 additions and 102 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "safe-dao-governance-app",
"homepage": "https://github.com/safe-global/safe-dao-governance-app",
"license": "GPL-3.0",
"version": "2.1.0",
"version": "2.2.0",
"scripts": {
"build": "next build && next export",
"lint": "tsc && next lint",
Expand Down
246 changes: 162 additions & 84 deletions src/components/Points/ActivityPointsFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,83 @@ import { GLOBAL_CAMPAIGN_IDS } from '@/config/constants'
import { Campaign } from '@/hooks/useCampaigns'
import { useChainId } from '@/hooks/useChainId'
import { useOwnCampaignRank } from '@/hooks/useLeaderboard'
import { formatDatetime } from '@/utils/date'
import { formatDate } from '@/utils/date'
import { Divider, Skeleton, Stack, Typography } from '@mui/material'
import Box from '@mui/material/Box'
import { useEffect, useMemo, useState } from 'react'
import { ReactNode, useEffect, useMemo, useState } from 'react'
import PointsCounter from '../PointsCounter'
import Barcode from '@/public/images/horizontal_barcode.svg'
import css from './styles.module.css'
import { useLatestCampaignUpdate } from '@/hooks/useLatestCampaignUpdate'

const BorderedBox = ({ children }: { children: ReactNode }) => {
return (
<Box
sx={{
border: ({ palette }) => `1px solid ${palette.border.light}`,
borderRadius: '6px',
p: '24px 32px',
display: 'flex',
flexDirection: 'column',
gap: 2,
position: 'relative',
}}
>
{children}
</Box>
)
}

const HiddenValue = () => (
<Typography minWidth="80px">
<Skeleton />
</Typography>
)

const DataWrapper = ({ children }: { children: ReactNode }) => {
return (
<Stack
direction={{ xs: 'column', lg: 'row' }}
justifyContent="space-between"
alignItems={{ xs: 'start', lg: 'center' }}
spacing={2}
>
{children}
</Stack>
)
}

export const ActivityPointsFeed = ({ campaign }: { campaign?: Campaign }) => {
const { data: ownEntry, isLoading } = useOwnCampaignRank(campaign?.resourceId)
const { data: latestUpdate, isLoading: isLatestUpdateLoading } = useLatestCampaignUpdate(campaign?.resourceId)

const data = useMemo(() => {
return {
activityPoints: ownEntry?.totalPoints ?? 0,
boostedPoints: ownEntry ? ownEntry.totalBoostedPoints - ownEntry.totalPoints : 0,
totalPoints: ownEntry?.totalBoostedPoints ?? 0,
activityPoints: latestUpdate?.totalPoints ?? 0,
boostedPoints: latestUpdate ? latestUpdate.totalBoostedPoints - latestUpdate.totalPoints : 0,
totalPoints: latestUpdate?.totalBoostedPoints ?? 0,
overallPoints: ownEntry?.totalBoostedPoints ?? 0,
}
}, [ownEntry])
}, [latestUpdate, ownEntry])

const [showBoostPoints, setShowBoostPoints] = useState(false)
const [showTotalPoints, setShowTotalPoints] = useState(false)
const [showOverallPoints, setShowOverallPoints] = useState(false)

useEffect(() => {
if (ownEntry !== undefined || !isLoading) {
const showBoostPointsTimeout = setTimeout(() => setShowBoostPoints(true), 1000)
const showTotalPointsTimeout = setTimeout(() => setShowTotalPoints(true), 2000)
if (isLoading || isLatestUpdateLoading) {
return
}
const showBoostPointsTimeout = setTimeout(() => setShowBoostPoints(true), 1000)
const showTotalPointsTimeout = setTimeout(() => setShowTotalPoints(true), 2000)
const showOverallPointsTimeout = setTimeout(() => setShowOverallPoints(true), 3000)

return () => {
clearTimeout(showBoostPointsTimeout)
clearTimeout(showTotalPointsTimeout)
}
return () => {
clearTimeout(showBoostPointsTimeout)
clearTimeout(showTotalPointsTimeout)
clearTimeout(showOverallPointsTimeout)
}
}, [ownEntry, isLoading])
}, [ownEntry, isLoading, isLatestUpdateLoading])

const chainId = useChainId()

Expand All @@ -53,81 +92,120 @@ export const ActivityPointsFeed = ({ campaign }: { campaign?: Campaign }) => {

if (isLoading) {
return (
<Box
key={campaign?.resourceId}
sx={{
border: ({ palette }) => `1px solid ${palette.border.light}`,
borderRadius: '6px',
p: '24px 32px',
display: 'flex',
flexDirection: 'column',
gap: 2,
position: 'relative',
}}
>
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
<Typography color="text.secondary">Activity points</Typography>
<HiddenValue />
</Stack>
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
<Typography color="text.secondary">Boost points</Typography>
<HiddenValue />
</Stack>
<Divider />
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
<Typography color="text.secondary">{!isGlobal && 'Campaign'} Total</Typography>
<HiddenValue />
</Stack>
<HiddenValue />
<Barcode className={css.barcode} />
</Box>
<>
<BorderedBox key={campaign?.resourceId}>
<DataWrapper>
<Typography color="text.secondary">Last drop</Typography>
<HiddenValue />
</DataWrapper>
<Divider
sx={{
marginRight: '-32px',
marginLeft: '-32px',
}}
/>
<DataWrapper>
<Typography color="text.secondary">Activity points</Typography>
<HiddenValue />
</DataWrapper>
<DataWrapper>
<Typography color="text.secondary">Boost points</Typography>
<HiddenValue />
</DataWrapper>
<Divider />
<DataWrapper>
<Typography color="text.secondary">{!isGlobal && 'Campaign'} Week total</Typography>
<HiddenValue />
</DataWrapper>
<Divider />
<DataWrapper>
<Typography color="text.secondary">{!isGlobal && 'Campaign'} Overall</Typography>
<HiddenValue />
</DataWrapper>
<Typography mt={6} alignSelf="center" color="text.secondary">
Your points are updated weekly.
</Typography>
<Barcode className={css.barcode} />
</BorderedBox>
{!isGlobal && (
<BorderedBox>
<DataWrapper>
<Typography color="text.secondary">Campaign total</Typography>
<HiddenValue />
</DataWrapper>
</BorderedBox>
)}
</>
)
}

return (
<Box
key={campaign?.resourceId}
sx={{
border: ({ palette }) => `1px solid ${palette.border.light}`,
borderRadius: '6px',
p: '24px 32px',
display: 'flex',
flexDirection: 'column',
gap: 2,
position: 'relative',
}}
>
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
<Typography color="text.secondary">Activity points</Typography>
<PointsCounter value={Number(data.activityPoints)} fontWeight={700}>
points
</PointsCounter>
</Stack>
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
<Typography color="text.secondary">Boost points</Typography>
{showBoostPoints ? (
<PointsCounter value={Number(data.boostedPoints)} fontWeight={700}>
points
</PointsCounter>
) : (
<HiddenValue />
)}
</Stack>
<Divider />
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
<Typography color="text.secondary">{!isGlobal && 'Campaign'} Total</Typography>
{showTotalPoints ? (
<PointsCounter value={Number(data.totalPoints)} fontWeight={700} fontSize="27px" color="primary">
<>
<BorderedBox key={campaign?.resourceId}>
<DataWrapper>
<Typography color="text.secondary">Your last drop</Typography>
{latestUpdate && (
<Typography color="text.secondary">
{formatDate(new Date(latestUpdate.startDate))} - {formatDate(new Date(latestUpdate.endDate))}
</Typography>
)}
</DataWrapper>
<Divider
sx={{
marginRight: '-32px',
marginLeft: '-32px',
}}
/>
<DataWrapper>
<Typography color="text.secondary">Activity points</Typography>
<PointsCounter value={Number(data.activityPoints)} fontWeight={700}>
points
</PointsCounter>
) : (
<HiddenValue />
)}
</Stack>
<Typography mt={6} alignSelf="center" color="text.secondary">
Last updated {formatDatetime(new Date(campaign.lastUpdated))}
</Typography>
<Barcode className={css.barcode} />
</Box>
</DataWrapper>
<DataWrapper>
<Typography color="text.secondary">Boost points</Typography>
{showBoostPoints ? (
<PointsCounter value={Number(data.boostedPoints)} fontWeight={700}>
points
</PointsCounter>
) : (
<HiddenValue />
)}
</DataWrapper>
<Divider />
<DataWrapper>
<Typography>{!isGlobal && 'Campaign'} Week total</Typography>
{showTotalPoints ? (
<PointsCounter value={Number(data.totalPoints)} fontWeight={700}>
points
</PointsCounter>
) : (
<HiddenValue />
)}
</DataWrapper>
<Typography mt={6} alignSelf="center" color="text.secondary">
Points are updated weekly.
</Typography>
<Typography mt={-2} alignSelf="center" color="text.secondary">
Last update: {formatDate(new Date(campaign.lastUpdated))}
</Typography>
<Barcode className={css.barcode} />
</BorderedBox>

{!isGlobal && (
<BorderedBox>
<DataWrapper>
<Typography color="text.secondary">Campaign total</Typography>
{showOverallPoints ? (
<PointsCounter value={Number(data.overallPoints)} fontWeight={700}>
points
</PointsCounter>
) : (
<HiddenValue />
)}
</DataWrapper>
</BorderedBox>
)}
</>
)
}
47 changes: 38 additions & 9 deletions src/components/Points/CampaignTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,44 @@
import * as React from 'react'
import Tabs from '@mui/material/Tabs'
import Tab from '@mui/material/Tab'
import { Box, Chip, Typography, useMediaQuery } from '@mui/material'
import { Box, Chip, Tooltip, Typography } from '@mui/material'
import { useTheme } from '@mui/material/styles'
import css from './styles.module.css'

const CAMPAIGN_TABS = [
{
label: 'Global',
label: (
<Typography display="flex" flexDirection="row" gap={1} alignItems="center" fontWeight={700}>
<Tooltip title="This campaign is active now" arrow>
<Box
sx={{
borderRadius: '100%',
backgroundColor: ({ palette }) => palette.primary.main,
minWidth: '6px',
minHeight: '6px',
flexShrink: 0,
marginRight: 1,
}}
/>
</Tooltip>
Global
</Typography>
),
disabled: false,
},
{
label: (
<Typography display="flex" flexDirection="row" gap={1} alignItems="center">
Campaigns <Chip variant="outlined" sx={{ borderRadius: '4px' }} label="soon" />
<Typography display="flex" flexDirection="row" gap={1} alignItems="center" fontWeight={700}>
<Box
sx={{
borderRadius: '100%',
backgroundColor: ({ palette }) => palette.text.disabled,
minWidth: '6px',
minHeight: '6px',
flexShrink: 0,
marginRight: 1,
}}
/>
Campaigns <Chip variant="outlined" className={css.comingSoon} label="soon" />
</Typography>
),
disabled: true,
Expand All @@ -21,19 +47,22 @@ const CAMPAIGN_TABS = [

const CampaignTabs = ({ onChange, selectedTabIdx }: { onChange: (tab: number) => void; selectedTabIdx: number }) => {
const theme = useTheme()
const isSmallScreen = useMediaQuery(theme.breakpoints.down('lg'))
return (
<Box padding="8px 0px">
<Tabs
orientation={isSmallScreen ? 'horizontal' : 'vertical'}
orientation="vertical"
variant="scrollable"
value={selectedTabIdx}
aria-label="Vertical tabs example"
sx={{ borderRight: 1, borderColor: 'divider' }}
sx={{ border: 1, borderColor: 'divider', borderRadius: '6px' }}
onChange={(_, value) => onChange(value)}
>
{CAMPAIGN_TABS.map((tab, tabIdx) => (
<Tab key={tabIdx} {...tab} />
<Tab
sx={{ textTransform: 'none', fontWeight: 700, textAlign: 'left', alignItems: 'start' }}
key={tabIdx}
{...tab}
/>
))}
</Tabs>
</Box>
Expand Down
Loading

0 comments on commit ca3cb78

Please sign in to comment.