diff --git a/apps/next/pages/account/rewards/lock-and-earn.tsx b/apps/next/pages/account/rewards/lock-and-earn.tsx new file mode 100644 index 000000000..6931f9522 --- /dev/null +++ b/apps/next/pages/account/rewards/lock-and-earn.tsx @@ -0,0 +1,26 @@ +import { LockAndEarnScreen } from 'app/features/account/rewards/lock/screen' +import Head from 'next/head' +import { userProtectedGetSSP } from 'utils/userProtected' +import type { NextPageWithLayout } from 'next-app/pages/_app' +import { HomeLayout } from 'app/features/home/layout.web' +import { ButtonOption, TopNav } from 'app/components/TopNav' + +export const Page: NextPageWithLayout = () => { + return ( + <> + + Send | Lock and Earn + + + + ) +} + +export const getServerSideProps = userProtectedGetSSP() +Page.getLayout = (children) => ( + }> + {children} + +) + +export default Page diff --git a/packages/app/components/icons/IconCoin.tsx b/packages/app/components/icons/IconCoin.tsx index a253f1931..4cafa2833 100644 --- a/packages/app/components/icons/IconCoin.tsx +++ b/packages/app/components/icons/IconCoin.tsx @@ -2,13 +2,14 @@ import type { coin } from 'app/data/coins' import { IconEthereum } from './IconEthereum' import { IconSend } from './IconSend' import { IconUSDC } from './IconUSDC' +import type { SizeTokens } from 'tamagui' -const coinSymbolToIcons: Record = { - USDC: , - ETH: , - SEND: , +const coinSymbolToIcons: Record JSX.Element> = { + USDC: (size) => , + ETH: (size) => , + SEND: (size) => , } -export const IconCoin = ({ coin }: { coin: coin }) => { - return coinSymbolToIcons[coin.symbol] +export const IconCoin = ({ coin, size }: { coin: coin; size?: SizeTokens }) => { + return coinSymbolToIcons[coin.symbol]?.(size || '$2.5') } diff --git a/packages/app/components/icons/IconExclamationCircle.tsx b/packages/app/components/icons/IconExclamationCircle.tsx new file mode 100644 index 000000000..93249a6d2 --- /dev/null +++ b/packages/app/components/icons/IconExclamationCircle.tsx @@ -0,0 +1,25 @@ +import type { ColorTokens } from '@my/ui/types' +import { type IconProps, themed } from '@tamagui/helpers-icon' +import { memo } from 'react' +import { Path, Svg } from 'react-native-svg' + +const ExclamationCircle = (props) => { + const { size, color, ...rest } = props + return ( + + + + ) +} +const IconExclamationCircle = memo(themed(ExclamationCircle)) +export { IconExclamationCircle } diff --git a/packages/app/components/icons/IconPlusCircle.tsx b/packages/app/components/icons/IconPlusCircle.tsx new file mode 100644 index 000000000..1ef485b66 --- /dev/null +++ b/packages/app/components/icons/IconPlusCircle.tsx @@ -0,0 +1,25 @@ +import type { ColorTokens } from '@my/ui/types' +import { type IconProps, themed } from '@tamagui/helpers-icon' +import { memo } from 'react' +import { Path, Svg } from 'react-native-svg' + +const PlusCircle = (props) => { + const { size, color, ...rest } = props + return ( + + + + ) +} +const IconPlusCircle = memo(themed(PlusCircle)) +export { IconPlusCircle } diff --git a/packages/app/components/icons/index.tsx b/packages/app/components/icons/index.tsx index 2eefa125b..7b111abdc 100644 --- a/packages/app/components/icons/index.tsx +++ b/packages/app/components/icons/index.tsx @@ -57,3 +57,5 @@ export { IconInfoCircle } from './IconInfoCircle' export { IconLeaderboard } from './IconLeaderboard' export { IconStarOutline } from './IconStarOutline' export { IconQuestionCircle } from './IconQuestionCircle' +export { IconPlusCircle } from './IconPlusCircle' +export { IconExclamationCircle } from './IconExclamationCircle' diff --git a/packages/app/features/account/rewards/lock/screen.tsx b/packages/app/features/account/rewards/lock/screen.tsx new file mode 100644 index 000000000..d38534577 --- /dev/null +++ b/packages/app/features/account/rewards/lock/screen.tsx @@ -0,0 +1,439 @@ +import { + YStack, + Card, + Paragraph, + H2, + XStack, + Spinner, + Tooltip, + type TooltipProps, + LinkableButton, + Button, + isWeb, + Stack, + AnimatePresence, + useMedia, + ScrollView, + LinearGradient, + usePwa, +} from '@my/ui' +import { + IconDollar, + IconError, + IconExclamationCircle, + IconPlus, + IconTriangleDown, +} from 'app/components/icons' +import { coins, type coin } from 'app/data/coins' +import { useSendAccount } from 'app/utils/send-accounts' +import { useBalance, type UseBalanceReturnType } from 'wagmi' +import { baseMainnet } from '@my/wagmi' +import formatAmount from 'app/utils/formatAmount' +import { IconCoin } from 'app/components/icons/IconCoin' +import { useState } from 'react' + +const ScrollLayout = ({ children }) => { + const isPwa = usePwa() + const media = useMedia() + + return ( + + {media.gtMd ? ( + children + ) : ( + <> + {/* @NOTE: This only works if passed a fixed height */} + + {children} + + + + + + + + + )} + + ) +} + +export function LockAndEarnScreen() { + return ( + + + + + + + + + + + ) +} + +const BalancesSection = () => { + return ( + +

+ Your Balances +

+ + {coins.map((coin) => { + return + })} + +
+ ) +} + +const TokenBalanceCard = ({ + coin, +}: { + coin: coin +}) => { + const { data: sendAccount } = useSendAccount() + const { gtMd } = useMedia() + const balance = useBalance({ + address: sendAccount?.address, + token: coin.token === 'eth' ? undefined : coin.token, + query: { enabled: !!sendAccount }, + chainId: baseMainnet.id, + }) + const iconSize = gtMd ? '$size.3.5' : '$size.1.5' + + return ( + + + + + + {coin.label} + + + + + + ) +} + +const TokenBalance = ({ balance }: { balance: UseBalanceReturnType }) => { + if (balance.isError) { + return ( + + + -- + + }> + Error occurred while fetching balance. {balance?.error?.message} + + + ) + } + + if (balance.isFetching && balance.isPending) { + return + } + if (balance?.data?.value === undefined) { + return <> + } + return ( + + {formatAmount( + (Number(balance.data?.value) / 10 ** (balance.data?.decimals ?? 0)).toString(), + 10, + 5 + )} + + ) +} + +// @TODO: This is duplicated from TokenBalanceList +const ErrorTooltip = ({ Icon, children, ...props }: TooltipProps & { Icon?: JSX.Element }) => { + return ( + + {Icon} + + + {children} + + + + ) +} + +const PositionsSection = () => { + const [positionsCount, setPositionsCount] = useState(4) + + return ( + +

+ Your Positions [{positionsCount}]{' '} + +

+ + + {positionsCount > 0 ? ( + [...Array(positionsCount)].map((n) => { + return + }) + ) : ( + + You don't have any open positions. + + )} + + + +
+ ) +} + +const PositionCard = () => { + const [isOpen, setIsOpen] = useState(false) + const [isClaimed, setIsClaimed] = useState(false) + + return ( + + + + + USDC/SEND + + + + + + + + + + {isOpen && ( + <> + + + + )} + + + + + + + {isOpen && ( + <> + + + + )} + + + + + ) +} + +const AddLiquidityButton = () => { + return ( + + ) +} + +const ClosePositionButton = () => { + return ( + + ) +} + +const PositionCardLineText = ({ left, right }: { left: string; right: string }) => { + return ( + + + {left} + + {right} + + ) +} + +const OpenPosition = () => { + return ( + + + + + + + + + + Open a New Position + + + + ) +}