Skip to content

Commit

Permalink
feat: add stake button on assets page
Browse files Browse the repository at this point in the history
fix: add area-label to stake button
  • Loading branch information
compojoom committed Sep 19, 2024
1 parent d2dd730 commit 12ad0b3
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 28 deletions.
2 changes: 1 addition & 1 deletion public/images/common/stake.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion src/components/balances/AssetsTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import CheckBalance from '@/features/counterfactual/CheckBalance'
import { type ReactElement } from 'react'
import { Tooltip, Typography, SvgIcon, IconButton, Box, Checkbox, Skeleton } from '@mui/material'
import { Box, IconButton, Checkbox, Skeleton, SvgIcon, Tooltip, Typography } from '@mui/material'
import type { TokenInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { TokenType } from '@safe-global/safe-gateway-typescript-sdk'
import css from './styles.module.css'
Expand All @@ -21,6 +21,9 @@ import SwapButton from '@/features/swap/components/SwapButton'
import { SWAP_LABELS } from '@/services/analytics/events/swaps'
import SendButton from './SendButton'
import useIsSwapFeatureEnabled from '@/features/swap/hooks/useIsSwapFeatureEnabled'
import useIsStakingFeatureEnabled from '@/features/stake/hooks/useIsSwapFeatureEnabled'
import { STAKE_LABELS } from '@/services/analytics/events/stake'
import StakeButton from '@/features/stake/components/StakeButton'

const skeletonCells: EnhancedTableProps['rows'][0]['cells'] = {
asset: {
Expand Down Expand Up @@ -97,6 +100,7 @@ const AssetsTable = ({
}): ReactElement => {
const { balances, loading } = useBalances()
const isSwapFeatureEnabled = useIsSwapFeatureEnabled()
const isStakingFeatureEnabled = useIsStakingFeatureEnabled()

const { isAssetSelected, toggleAsset, hidingAsset, hideAsset, cancel, deselectAll, saveChanges } = useHideAssets(() =>
setShowHiddenAssets(false),
Expand Down Expand Up @@ -130,6 +134,10 @@ const AssetsTable = ({

<Typography>{item.tokenInfo.name}</Typography>

{isStakingFeatureEnabled && item.tokenInfo.type === TokenType.NATIVE_TOKEN && (
<StakeButton tokenInfo={item.tokenInfo} trackingLabel={STAKE_LABELS.asset} />
)}

{!isNative && <TokenExplorerLink address={item.tokenInfo.address} />}
</div>
),
Expand Down
58 changes: 58 additions & 0 deletions src/features/stake/components/StakeButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import CheckWallet from '@/components/common/CheckWallet'
import Track from '@/components/common/Track'
import { AppRoutes } from '@/config/routes'
import useSpendingLimit from '@/hooks/useSpendingLimit'
import { Button } from '@mui/material'
import type { TokenInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { TokenType } from '@safe-global/safe-gateway-typescript-sdk'
import { useRouter } from 'next/router'
import type { ReactElement } from 'react'
import StakeIcon from '@/public/images/common/stake.svg'
import type { STAKE_LABELS } from '@/services/analytics/events/stake'
import { STAKE_EVENTS } from '@/services/analytics/events/stake'
import { useCurrentChain } from '@/hooks/useChains'

const StakeButton = ({
tokenInfo,
trackingLabel,
}: {
tokenInfo: TokenInfo
trackingLabel: STAKE_LABELS
}): ReactElement => {
const spendingLimit = useSpendingLimit(tokenInfo)
const chain = useCurrentChain()
const router = useRouter()

return (
<CheckWallet allowSpendingLimit={!!spendingLimit}>
{(isOk) => (
<Track {...STAKE_EVENTS.OPEN_STAKE} label={trackingLabel}>
<Button
data-testid="stake-btn"
aria-label="Stake"
variant="text"
color="info"
size="small"
startIcon={<StakeIcon />}
onClick={() => {
router.push({
pathname: AppRoutes.stake,
query: {
...router.query,
asset: `${chain?.shortName}_${
tokenInfo.type === TokenType.NATIVE_TOKEN ? 'NATIVE_TOKEN' : tokenInfo.address
}`,
},
})
}}
disabled={!isOk}
>
Stake
</Button>
</Track>
)}
</CheckWallet>
)
}

export default StakeButton
5 changes: 4 additions & 1 deletion src/features/stake/components/StakePage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import Disclaimer from '@/components/common/Disclaimer'
import WidgetDisclaimer from '@/components/common/WidgetDisclaimer'
import useStakeConsent from '@/features/stake/useStakeConsent'
import StakingWidget from '../StakingWidget'
import { useRouter } from 'next/router'

const StakePage = () => {
const { isConsentAccepted, onAccept } = useStakeConsent()
const router = useRouter()
const { asset } = router.query

return (
<>
{isConsentAccepted === undefined ? null : isConsentAccepted ? (
<StakingWidget />
<StakingWidget asset={String(asset)} />
) : (
<Stack direction="column" alignItems="center" justifyContent="center" flex={1}>
<Disclaimer
Expand Down
31 changes: 6 additions & 25 deletions src/features/stake/components/StakingWidget/index.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,19 @@
import { useMemo } from 'react'
import { useDarkMode } from '@/hooks/useDarkMode'
import AppFrame from '@/components/safe-apps/AppFrame'
import { getEmptySafeApp } from '@/components/safe-apps/utils'
import useChainId from '@/hooks/useChainId'
import useChains from '@/hooks/useChains'
import { useGetStakeWidgetUrl } from '@/features/stake/hooks/useGetStakeWidgetUrl'
import { widgetAppData } from '@/features/stake/constants'

const WIDGET_PRODUCTION_URL = 'https://safe.widget.kiln.fi/earn'
const WIDGET_TESTNET_URL = 'https://safe.widget.testnet.kiln.fi/earn'
const widgetAppData = {
url: WIDGET_PRODUCTION_URL,
name: 'Stake',
iconUrl: '/images/common/stake.svg',
chainIds: ['17000', '11155111', '1', '42161', '137', '56', '8453', '10'],
}

const StakingWidget = () => {
const isDarkMode = useDarkMode()
let url = widgetAppData.url
const currentChainId = useChainId()
const { configs } = useChains()
const testChains = useMemo(() => configs.filter((chain) => chain.isTestnet), [configs])

// if currentChainId is in testChains, then set the url to the testnet version
if (testChains.some((chain) => chain.chainId === currentChainId)) {
url = WIDGET_TESTNET_URL
}
const StakingWidget = ({ asset }: { asset?: string }) => {
const url = useGetStakeWidgetUrl(asset)

const appData = useMemo(
() => ({
...getEmptySafeApp(),
...widgetAppData,
url: url + `?theme=${isDarkMode ? 'dark' : 'light'}`,
url,
}),
[isDarkMode, url],
[url],
)

return (
Expand Down
10 changes: 10 additions & 0 deletions src/features/stake/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
export const STAKE_TITLE = 'Stake'

export const WIDGET_PRODUCTION_URL = 'https://safe.widget.kiln.fi/earn'
export const WIDGET_TESTNET_URL = 'https://safe.widget.testnet.kiln.fi/earn'

export const widgetAppData = {
url: WIDGET_PRODUCTION_URL,
name: STAKE_TITLE,
iconUrl: '/images/common/stake.svg',
chainIds: ['17000', '11155111', '1', '42161', '137', '56', '8453', '10'],
}
24 changes: 24 additions & 0 deletions src/features/stake/hooks/useGetStakeWidgetUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useDarkMode } from '@/hooks/useDarkMode'
import useChainId from '@/hooks/useChainId'
import useChains from '@/hooks/useChains'
import { useMemo } from 'react'
import { WIDGET_PRODUCTION_URL, WIDGET_TESTNET_URL } from '@/features/stake/constants'

export const useGetStakeWidgetUrl = (asset?: string) => {
let url = WIDGET_PRODUCTION_URL
const isDarkMode = useDarkMode()
const currentChainId = useChainId()
const { configs } = useChains()
const testChains = useMemo(() => configs.filter((chain) => chain.isTestnet), [configs])
if (testChains.some((chain) => chain.chainId === currentChainId)) {
url = WIDGET_TESTNET_URL
}
const params = new URLSearchParams()
params.append('theme', isDarkMode ? 'dark' : 'light')

if (asset) {
params.append('asset', asset)
}

return url + '?' + params.toString()
}
11 changes: 11 additions & 0 deletions src/features/stake/hooks/useIsSwapFeatureEnabled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { GeoblockingContext } from '@/components/common/GeoblockingProvider'
import { useHasFeature } from '@/hooks/useChains'
import { FEATURES } from '@/utils/chains'
import { useContext } from 'react'

const useIsStakingFeatureEnabled = () => {
const isBlockedCountry = useContext(GeoblockingContext)
return useHasFeature(FEATURES.STAKING) && !isBlockedCountry
}

export default useIsStakingFeatureEnabled
14 changes: 14 additions & 0 deletions src/services/analytics/events/stake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const STAKE_CATEGORY = 'stake'

export const STAKE_EVENTS = {
OPEN_STAKE: {
action: 'Open stake',
category: STAKE_CATEGORY,
},
}

export enum STAKE_LABELS {
dashboard = 'dashboard',
sidebar = 'sidebar',
asset = 'asset',
}

0 comments on commit 12ad0b3

Please sign in to comment.