diff --git a/apps/evm/package.json b/apps/evm/package.json index 4fccf7535..62473c0c5 100644 --- a/apps/evm/package.json +++ b/apps/evm/package.json @@ -37,7 +37,6 @@ "@sentry/nextjs": "catalog:", "@tanstack/react-query": "catalog:", "@tanstack/react-store": "catalog:", - "@tanstack/react-virtual": "catalog:", "@vercel/kv": "catalog:", "@wagmi/core": "catalog:", "big.js": "catalog:", diff --git a/apps/evm/src/app/[lang]/(bridge)/bridge/Bridge.style.tsx b/apps/evm/src/app/[lang]/(bridge)/bridge/Bridge.style.tsx index 1de0a9331..c1305221c 100644 --- a/apps/evm/src/app/[lang]/(bridge)/bridge/Bridge.style.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/bridge/Bridge.style.tsx @@ -1,12 +1,9 @@ -import { Card, Flex } from '@gobob/ui'; +import { Card } from '@gobob/ui'; import styled from 'styled-components'; -const StyledFlex = styled(Flex)` - width: 100%; -`; - const StyledCard = styled(Card)` width: 100%; + min-width: 100%; `; -export { StyledCard, StyledFlex }; +export { StyledCard }; diff --git a/apps/evm/src/app/[lang]/(bridge)/bridge/Bridge.tsx b/apps/evm/src/app/[lang]/(bridge)/bridge/Bridge.tsx index db714970d..6de797cbe 100644 --- a/apps/evm/src/app/[lang]/(bridge)/bridge/Bridge.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/bridge/Bridge.tsx @@ -1,18 +1,23 @@ 'use client'; import { ChainId, getChainIdByChainName, getChainName } from '@gobob/chains'; -import { Tabs, TabsItem } from '@gobob/ui'; +import { useAccount as useSatsAccount } from '@gobob/sats-wagmi'; +import { Button, Card, Flex, Skeleton, SolidClock, Span, Spinner, Tabs, TabsItem } from '@gobob/ui'; import { Trans } from '@lingui/macro'; import { useRouter } from 'next/navigation'; import { Key, useCallback, useEffect, useMemo, useState } from 'react'; +import { useAccount } from 'wagmi'; -import { Layout, TransactionList } from '../components'; +import { BannerCarousel } from '../components/BannerCarousel'; -import { StyledCard, StyledFlex } from './Bridge.style'; +import { StyledCard } from './Bridge.style'; import { BridgeForm } from './components'; -import { useGetTransactions } from './hooks'; +import { Main } from '@/components'; +import { useConnectModal } from '@/connect-ui'; import { L1_CHAIN, L2_CHAIN } from '@/constants'; +import { useGetBridgeTransactions } from '@/hooks'; +import { SharedStoreProfileTxStatus, SharedStoreProfileTxType, store } from '@/lib/store'; import { TransactionDirection } from '@/types'; const externalUnsupportedTokens = ['LBTC']; @@ -50,15 +55,16 @@ interface Props { } const Bridge = ({ searchParams }: Props) => { - const { - data: transactions, - isInitialLoading: isTransactionsInitialLoading, - refetch, - txPendingUserAction - } = useGetTransactions(); - const router = useRouter(); + const { txPendingUserAction, isPending } = useGetBridgeTransactions(); + const { open } = useConnectModal(); + + const { address: evmAddress } = useAccount(); + const { address: btcAddress } = useSatsAccount(); + + const isLoggedIn = !!(evmAddress || btcAddress); + const urlSearchParams = useMemo(() => new URLSearchParams(searchParams), [searchParams]); const type = (urlSearchParams.get('type') as Type) || Type.Deposit; const direction = type === Type.Deposit ? TransactionDirection.L1_TO_L2 : TransactionDirection.L2_TO_L1; @@ -122,6 +128,37 @@ const Bridge = ({ searchParams }: Props) => { urlSearchParams.set('network', network); }; + const hasPendingTx = txPendingUserAction && txPendingUserAction > 0; + + const handleOpenProfile = () => { + store.setState((state) => ({ + ...state, + shared: { + ...state.shared, + profile: { + ...state.shared.profile, + isOpen: true, + selectedTab: 'activity', + transactions: { + filters: { + ...state.shared.profile.transactions.filters, + status: hasPendingTx ? SharedStoreProfileTxStatus.NEEDED_ACTION : undefined, + type: SharedStoreProfileTxType.NATIVE_BRIDGE + } + } + } + } + })); + }; + + const handleActivity = () => { + if (!isLoggedIn) { + return open({ onConnectBtc: handleOpenProfile, onConnectEvm: handleOpenProfile }); + } + + handleOpenProfile(); + }; + useEffect(() => { const chain = getChain(); @@ -140,51 +177,72 @@ const Bridge = ({ searchParams }: Props) => { const tabsDisabledKeys = isWithdrawTabDisabled ? [Type.Withdraw] : undefined; return ( - - - - - Deposit}> - <> - - Withdraw} - tooltipProps={{ - isDisabled: !isWithdrawTabDisabled, - label: Withdrawals back to BTC are currently not supported - }} +
+ + + + + + + + - <> - - - - - - - + Deposit}> + <> + + Withdraw} + tooltipProps={{ + isDisabled: !isWithdrawTabDisabled, + label: Withdrawals back to BTC are currently not supported + }} + > + <> + + + + + + +
); }; diff --git a/apps/evm/src/app/[lang]/(bridge)/bridge/components/BridgeForm/BobBridgeForm.tsx b/apps/evm/src/app/[lang]/(bridge)/bridge/components/BridgeForm/BobBridgeForm.tsx index 3e305d48b..b4ceff244 100644 --- a/apps/evm/src/app/[lang]/(bridge)/bridge/components/BridgeForm/BobBridgeForm.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/bridge/components/BridgeForm/BobBridgeForm.tsx @@ -205,7 +205,8 @@ const BobBridgeForm = ({ to: recipient, l1Token: l1Address, l2Token: l2Address, - type: TransactionType.Bridge + type: TransactionType.Bridge, + logoUrl: selectedToken.l1Token.logoUrl }; const to = recipient || address!; @@ -297,7 +298,8 @@ const BobBridgeForm = ({ to: recipient, l1Token: l1Address, l2Token: l2Address, - type: TransactionType.Bridge + type: TransactionType.Bridge, + logoUrl: selectedToken.l2Token.logoUrl }; const to = recipient || address!; diff --git a/apps/evm/src/app/[lang]/(bridge)/bridge/components/BridgeForm/BridgeForm.tsx b/apps/evm/src/app/[lang]/(bridge)/bridge/components/BridgeForm/BridgeForm.tsx index b6661bcf4..6d821cc07 100644 --- a/apps/evm/src/app/[lang]/(bridge)/bridge/components/BridgeForm/BridgeForm.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/bridge/components/BridgeForm/BridgeForm.tsx @@ -13,7 +13,6 @@ import { useAccount as useSatsAccount } from '@gobob/sats-wagmi'; import { BridgeTransactionModal, GatewayTransactionModal } from '../../../components'; import { BridgeOrigin } from '../../Bridge'; -import { useGetTransactions } from '../../hooks'; import { ChainSelect } from '../ChainSelect'; import { ExternalBridgeForm } from '../ExternalBridgeForm'; @@ -22,7 +21,7 @@ import { StyledChainsGrid, StyledRadio } from './BridgeForm.style'; import { BtcBridgeForm } from './BtcBridgeForm'; import { INTERVAL, L1_CHAIN, L2_CHAIN } from '@/constants'; -import { TokenData } from '@/hooks'; +import { TokenData, useGetBridgeTransactions, useGetGatewayTransactions } from '@/hooks'; import { gatewaySDK } from '@/lib/bob-sdk'; import { bridgeKeys } from '@/lib/react-query'; import { BridgeTransaction, InitBridgeTransaction, InitGatewayTransaction, TransactionDirection } from '@/types'; @@ -80,7 +79,9 @@ const BridgeForm = ({ const { i18n } = useLingui(); const { connector } = useSatsAccount(); - const { refetch: refetchTransactions, addPlaceholderTransaction } = useGetTransactions(); + const { refetch: refetchBridgeTransactions, addPlaceholderTransaction: addBridgePlaceholderTransaction } = + useGetBridgeTransactions(); + const { refetch: refetchGatewayTransactions } = useGetGatewayTransactions(); const [bridgeModalState, setBridgeModalState] = useState({ isOpen: false, @@ -120,9 +121,9 @@ const BridgeForm = ({ }; const handleBridgeSuccess = (data: BridgeTransaction) => { - addPlaceholderTransaction.bridge(data); + addBridgePlaceholderTransaction(data); - refetchTransactions.bridge(); + refetchBridgeTransactions(); setBridgeModalState({ isOpen: true, data, step: 'submitted' }); }; @@ -140,7 +141,7 @@ const BridgeForm = ({ }; const handleGatewaySuccess = (data: InitGatewayTransaction) => { - refetchTransactions.gateway(); + refetchGatewayTransactions(); setGatewayModalState({ isOpen: true, data }); diff --git a/apps/evm/src/app/[lang]/(bridge)/bridge/hooks/index.ts b/apps/evm/src/app/[lang]/(bridge)/bridge/hooks/index.ts deleted file mode 100644 index de7ffb372..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/bridge/hooks/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './useGetTransactions'; diff --git a/apps/evm/src/app/[lang]/(bridge)/bridge/hooks/useGetTransactions.ts b/apps/evm/src/app/[lang]/(bridge)/bridge/hooks/useGetTransactions.ts deleted file mode 100644 index 8cbf63240..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/bridge/hooks/useGetTransactions.ts +++ /dev/null @@ -1,75 +0,0 @@ -'use client'; - -import { useStore } from '@tanstack/react-store'; -import { watchAccount } from '@wagmi/core'; -import { useEffect, useMemo, useRef } from 'react'; -import { useConfig } from 'wagmi'; - -import { GetGatewayTransactionsReturnType, useGetBridgeTransactions, useGetGatewayTransactions } from '../../hooks'; - -import { store } from '@/lib/store'; -import { GatewayTransactionType } from '@/types'; - -const select = (data: GetGatewayTransactionsReturnType) => - data.filter((item) => item.subType === GatewayTransactionType.BRIDGE); - -const useGetTransactions = () => { - const config = useConfig(); - const gateway = useGetGatewayTransactions({ - query: { select } - }); - const bridge = useGetBridgeTransactions(); - - const isInitialLoading = useStore(store, (state) => state.bridge.transactions.isInitialLoading); - - const isLoading = gateway.isLoading || bridge.isLoading; - - const watchAccountRef = useRef<() => void>(); - - useEffect(() => { - watchAccountRef.current = watchAccount(config, { - onChange: (account) => { - if (account.address) { - store.setState((state) => ({ - ...state, - bridge: { ...state.bridge, transactions: { ...state.bridge.transactions, isInitialLoading: true } } - })); - } - } - }); - - // Cleanup by calling unwatch to unsubscribe from the account change event - return () => watchAccountRef.current?.(); - }, [config]); - - useEffect(() => { - if (isInitialLoading && !isLoading) { - store.setState((state) => ({ - ...state, - bridge: { ...state.bridge, transactions: { ...state.bridge.transactions, isInitialLoading: false } } - })); - } - }, [isInitialLoading, isLoading]); - - const data = useMemo(() => { - const data = [...(gateway.data || []), ...bridge.data]; - - return data?.sort((a, b) => b.date.getTime() - a.date.getTime()); - }, [bridge.data, gateway.data]); - - return { - data, - refetch: { - gateway: gateway.refetch, - bridge: bridge.refetch - }, - addPlaceholderTransaction: { - bridge: bridge.addPlaceholderTransaction - }, - txPendingUserAction: bridge.txPendingUserAction, - isInitialLoading, - isLoading - }; -}; - -export { useGetTransactions }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BabylonBanner.tsx b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BabylonBanner.tsx index 4f1a113aa..732c36f33 100644 --- a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BabylonBanner.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BabylonBanner.tsx @@ -9,9 +9,10 @@ import { BannerTitle } from './BannerTitle'; type FusionBannerProps = { onPress?: () => void; + hasImgOpacity?: boolean; }; -const BabylonBanner = ({ onPress }: FusionBannerProps) => { +const BabylonBanner = ({ hasImgOpacity, onPress }: FusionBannerProps) => { const { i18n } = useLingui(); return ( @@ -29,7 +30,14 @@ const BabylonBanner = ({ onPress }: FusionBannerProps) => {

- + ); }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BannerCarousel.style.tsx b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BannerCarousel.style.tsx index 3b5a4d024..e7575d1f0 100644 --- a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BannerCarousel.style.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BannerCarousel.style.tsx @@ -3,6 +3,10 @@ import Image from 'next/image'; import Carousel from 'react-multi-carousel'; import styled, { css } from 'styled-components'; +type StyledImgProps = { + $hasImgOpacity?: boolean; +}; + const StyledCarouselWrapper = styled(Card)` position: relative; text-decoration: none; @@ -64,13 +68,15 @@ const StyledBannerTitle = styled(H1)` text-overflow: ellipsis; `; -const StyledImg = styled(Image)` - ${({ theme }) => { +const StyledImg = styled(Image)` + ${({ theme, $hasImgOpacity }) => { return css` position: absolute; top: 50%; right: 0; transform: translateY(-50%); + opacity: ${$hasImgOpacity && 0.2}; + @media ${theme.breakpoints.down('md')} { opacity: 0.2; } diff --git a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BannerCarousel.tsx b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BannerCarousel.tsx index bea16a561..c27d592ad 100644 --- a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BannerCarousel.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/BannerCarousel.tsx @@ -1,19 +1,21 @@ 'use client'; -import { useMediaQuery } from '@gobob/ui'; +import { CardProps, useMediaQuery } from '@gobob/ui'; import { t } from '@lingui/macro'; import { useLingui } from '@lingui/react'; import { useCallback, useMemo } from 'react'; import 'react-multi-carousel/lib/styles.css'; import { useTheme } from 'styled-components'; +import { BabylonBanner } from './BabylonBanner'; import { StyledCarousel, StyledCarouselWrapper } from './BannerCarousel.style'; import { FusionBanner } from './FusionBanner'; -import { XBanner } from './XBanner'; import { HybridL2Banner } from './HybridL2Banner'; -import { BabylonBanner } from './BabylonBanner'; +import { XBanner } from './XBanner'; + +type BannerCarouselProps = Omit & { hasImgOpacity?: boolean }; -const BannerCarousel = () => { +const BannerCarousel = ({ hasImgOpacity, ...props }: BannerCarouselProps) => { const { i18n } = useLingui(); const theme = useTheme(); const isDesktop = useMediaQuery(theme.breakpoints.up('s')); @@ -69,11 +71,7 @@ const BannerCarousel = () => { ); return ( - + { swipeable={false} transitionDuration={500} > - - - - + + + + ); diff --git a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/FusionBanner.tsx b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/FusionBanner.tsx index 8036b8019..ef18d4bb2 100644 --- a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/FusionBanner.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/FusionBanner.tsx @@ -9,9 +9,10 @@ import { BannerTitle } from './BannerTitle'; type FusionBannerProps = { onPress?: () => void; + hasImgOpacity?: boolean; }; -const FusionBanner = ({ onPress }: FusionBannerProps) => { +const FusionBanner = ({ onPress, hasImgOpacity }: FusionBannerProps) => { const { i18n } = useLingui(); return ( @@ -27,6 +28,7 @@ const FusionBanner = ({ onPress }: FusionBannerProps) => {

void; + hasImgOpacity?: boolean; }; -const HybridL2Banner = ({ onPress }: HybridL2BannerProps) => { +const HybridL2Banner = ({ hasImgOpacity, onPress }: HybridL2BannerProps) => { const { i18n } = useLingui(); return ( @@ -26,7 +27,14 @@ const HybridL2Banner = ({ onPress }: HybridL2BannerProps) => { Read it now.

- + ); }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/XBanner.tsx b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/XBanner.tsx index 99d52f99c..6cb888110 100644 --- a/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/XBanner.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/components/BannerCarousel/XBanner.tsx @@ -8,9 +8,10 @@ import { BannerTitle } from './BannerTitle'; type XBannerProps = { onPress?: () => void; + hasImgOpacity?: boolean; }; -const XBanner = ({ onPress }: XBannerProps) => ( +const XBanner = ({ hasImgOpacity, onPress }: XBannerProps) => ( @@ -22,7 +23,7 @@ const XBanner = ({ onPress }: XBannerProps) => ( To stay up-to date with the BOB ecosystem follow @build_on_bob.

- +
); diff --git a/apps/evm/src/app/[lang]/(bridge)/components/Layout/Layout.tsx b/apps/evm/src/app/[lang]/(bridge)/components/Layout/Layout.tsx deleted file mode 100644 index 97164229c..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/components/Layout/Layout.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { BannerCarousel } from '../BannerCarousel'; - -import { Main } from '@/components'; - -const Layout = ({ children }: { children: React.ReactNode }) => { - return ( -
- - {children} -
- ); -}; - -export { Layout }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/Layout/index.tsx b/apps/evm/src/app/[lang]/(bridge)/components/Layout/index.tsx deleted file mode 100644 index 9fc685e2a..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/components/Layout/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { Layout } from './Layout'; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/BridgeTransactionItem.tsx b/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/BridgeTransactionItem.tsx deleted file mode 100644 index d5ac306e9..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/BridgeTransactionItem.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Flex, FlexProps } from '@gobob/ui'; -import { useState } from 'react'; - -import { BridgeTransaction } from '../../hooks'; -import { BridgeStatus } from '../BridgeStatus'; - -import { TransactionDetails } from './TransactionDetails'; - -import { L1_CHAIN, L2_CHAIN } from '@/constants'; -import { TransactionDirection } from '@/types'; - -type Props = { data: BridgeTransaction; onProveSuccess?: () => void; onRelaySuccess?: () => void }; - -type InheritAttrs = Omit; - -type BridgeTransactionItemProps = Props & InheritAttrs; - -const BridgeTransactionItem = ({ - data, - onProveSuccess, - onRelaySuccess, - ...props -}: BridgeTransactionItemProps): JSX.Element => { - const [isExpanded, setExpanded] = useState(false); - - const fromChaindId = data.direction === TransactionDirection.L1_TO_L2 ? L1_CHAIN : L2_CHAIN; - const toChaindId = data.direction === TransactionDirection.L1_TO_L2 ? L2_CHAIN : L1_CHAIN; - - return ( - - setExpanded((isExpanded) => !isExpanded)} - /> - - - ); -}; - -export { BridgeTransactionItem }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/GatewayTransactionItem.tsx b/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/GatewayTransactionItem.tsx deleted file mode 100644 index 24db66da4..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/GatewayTransactionItem.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Flex, FlexProps } from '@gobob/ui'; -import { useState } from 'react'; - -import { GatewayTransaction } from '../../hooks'; -import { GatewayStatus } from '../GatewayStatus'; - -import { TransactionDetails } from './TransactionDetails'; - -import { L2_CHAIN } from '@/constants'; -import { TransactionDirection } from '@/types'; - -type Props = { data: GatewayTransaction }; - -type InheritAttrs = Omit; - -type GatewayTransactionItemProps = Props & InheritAttrs; - -const GatewayTransactionItem = ({ data, ...props }: GatewayTransactionItemProps): JSX.Element => { - const [isExpanded, setExpanded] = useState(false); - - const fromChaindId = 'BTC'; - const toChaindId = L2_CHAIN; - - return ( - - setExpanded((isExpanded) => !isExpanded)} - /> - - - ); -}; - -export { GatewayTransactionItem }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionDetails.tsx b/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionDetails.tsx deleted file mode 100644 index 776e56f39..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionDetails.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { ChainId } from '@gobob/chains'; -import { Currency, CurrencyAmount } from '@gobob/currency'; -import { ArrowLongRight, Flex, FlexProps, P, UnstyledButton } from '@gobob/ui'; -import { Trans } from '@lingui/macro'; -import { formatDistanceToNow } from 'date-fns'; -import { useParams } from 'next/navigation'; - -import { StyledDetailsButton, StyledExpandIcon } from './TransactionList.style'; - -import { Chain } from '@/components'; -import { TransactionDirection } from '@/types'; -import { getLocale } from '@/utils'; - -type Props = { - direction: TransactionDirection; - date: Date; - fromChainId: ChainId | 'BTC'; - toChainId: ChainId | 'BTC'; - amount?: CurrencyAmount; - isPending?: boolean; - isExpanded?: boolean; - onExpand?: () => void; -}; - -type InheritAttrs = Omit; - -type TransactionDetailsProps = Props & InheritAttrs; - -const TransactionDetails = ({ - direction, - date, - fromChainId, - toChainId, - amount, - isPending, - isExpanded, - onExpand, - ...props -}: TransactionDetailsProps): JSX.Element => { - const { lang } = useParams(); - const directionLabel = direction === TransactionDirection.L1_TO_L2 ? Deposit : Withdraw; - - const isExpandable = !!onExpand; - - return ( - - -

- {directionLabel} -

-

- {formatDistanceToNow(date, { locale: getLocale(lang as Parameters[0]) })} ago -

-
- - - - - - - - - {(isPending && ( -

- Pending -

- )) || - (amount && ( -

- {amount.toExact()} {amount.currency.symbol} -

- )) || ( -

- Unknown -

- )} - {isExpandable && } -
-
-
-
- ); -}; - -export { TransactionDetails }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionList.style.tsx b/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionList.style.tsx deleted file mode 100644 index 19ed1e6b2..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionList.style.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Card, Flex, Span, ArrowDownCircle } from '@gobob/ui'; -import styled from 'styled-components'; - -type StyledExpandIconProps = { - $isExpanded?: boolean; -}; - -type StyledVirtualizerProps = { - $height: number; -}; - -type StyledVirtualizerItemProps = { - $translateY: number; -}; - -const StyledSection = styled(Card)` - width: 100%; - overflow: hidden; - max-height: calc(100vh - 16rem); - min-height: 35rem; -`; - -const StyledSpan = styled(Span)` - display: inline-flex; - align-items: center; - position: relative; - margin-left: ${({ theme }) => theme.spacing('md')}; - padding: 0 ${({ theme }) => theme.spacing('s')}; - height: 24px; - border-radius: ${({ theme }) => theme.rounded('full')}; -`; - -const StyledSpinnerWrapper = styled.span` - position: absolute; - top: 0; - left: 50%; - transform: translateX(-50%); -`; - -const StyledTransactionList = styled(Flex)` - overflow-y: auto; - flex: 1 1 auto; -`; - -const StyledTransactionListWrapper = styled(Flex)` - overflow: hidden; -`; - -const StyledTransactionListParent = styled.div` - height: 610px; - overflow: auto; -`; - -const StyledVirtualizer = styled.div` - width: 100%; - position: relative; - height: ${({ $height }) => `${$height}px`}; -`; - -const StyledVirtualizerItem = styled.div` - position: absolute; - width: 100%; - transform: ${({ $translateY }) => `translateY(${$translateY}px)`}; -`; - -const StyledDetailsButton = styled(Flex)` - font: inherit; - display: flex; - width: 100%; - flex-direction: column; - gap: ${({ theme }) => theme.spacing('md')}; - padding: ${({ theme }) => `${theme.spacing('md')} 0`}; -`; - -const StyledExpandIcon = styled(ArrowDownCircle)` - ${({ theme }) => theme.transition('common', 'normal')}; - transform: ${({ $isExpanded }) => ($isExpanded ? 'rotate(-180deg)' : 'rotate(0deg)')}; -`; - -export { - StyledDetailsButton, - StyledExpandIcon, - StyledSection, - StyledSpan, - StyledSpinnerWrapper, - StyledTransactionList, - StyledTransactionListWrapper, - StyledTransactionListParent, - StyledVirtualizer, - StyledVirtualizerItem -}; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionList.tsx b/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionList.tsx deleted file mode 100644 index 0d186bd89..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/TransactionList.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import { CardProps, Divider, Flex, H2, Link, P, Spinner } from '@gobob/ui'; -import { Trans } from '@lingui/macro'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useMemo, useRef } from 'react'; -import { useIsClient } from 'usehooks-ts'; -import { useAccount } from 'wagmi'; - -import { TransactionItem } from './TransactionItem'; -import { - StyledSection, - StyledSpan, - StyledSpinnerWrapper, - StyledTransactionList, - StyledTransactionListParent, - StyledTransactionListWrapper, - StyledVirtualizer, - StyledVirtualizerItem -} from './TransactionList.style'; - -import { chainL2 } from '@/constants'; -import { Transaction } from '@/types'; - -type Props = { - isInitialLoading?: boolean; - data?: Transaction[]; - onProveSuccess?: () => void; - onRelaySuccess?: () => void; - txPendingUserAction?: number; -}; - -type InheritAttrs = Omit; - -type TransactionListProps = Props & InheritAttrs; - -const TransactionList = ({ - isInitialLoading, - data, - onProveSuccess, - onRelaySuccess, - txPendingUserAction, - ...props -}: TransactionListProps): JSX.Element => { - const isClient = useIsClient(); - // The scrollable element for your list - const parentRef = useRef(null); - - // The virtualizer - const rowVirtualizer = useVirtualizer({ - count: data?.length || 0, - getScrollElement: () => parentRef.current, - estimateSize: () => 102, - paddingStart: 16, - paddingEnd: 16, - gap: 16, - measureElement: (element) => element?.getBoundingClientRect().height, - overscan: 5 - }); - - const { address, chain } = useAccount(); - - const title = ( - - Activity - {!!txPendingUserAction && ( - - {txPendingUserAction} - - - - - )} - - ); - - const explorerUrl = useMemo(() => (chain || chainL2).blockExplorers?.default.url, [chain]); - - const txsUrl = address ? `${explorerUrl}/address/${address}` : `${explorerUrl}`; - const hasData = !!data?.length; - - return ( - -

{title}

- - - - {!isClient || isInitialLoading ? ( - - -

- Fetching operations... -

-
- ) : ( - <> - {hasData ? ( - - - {rowVirtualizer.getVirtualItems().map((virtualItem) => ( - rowVirtualizer.measureElement(node)} //measure dynamic row height - $translateY={virtualItem.start} - data-index={virtualItem.index} //needed for dynamic row height measurement - > - - {virtualItem.index < data.length - 1 && } - - ))} - - - ) : ( - -

- No operations found -

-
- )} - - )} -
- -
- - View All Transactions - -
- ); -}; - -export { TransactionList }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/index.tsx b/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/index.tsx deleted file mode 100644 index 30e9c699e..000000000 --- a/apps/evm/src/app/[lang]/(bridge)/components/TransactionList/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { TransactionList } from './TransactionList'; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/TransactionModal/GatewayTransactionModal.tsx b/apps/evm/src/app/[lang]/(bridge)/components/TransactionModal/GatewayTransactionModal.tsx index 2b16733ba..126a7a13d 100644 --- a/apps/evm/src/app/[lang]/(bridge)/components/TransactionModal/GatewayTransactionModal.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/components/TransactionModal/GatewayTransactionModal.tsx @@ -17,10 +17,9 @@ import { } from '@gobob/ui'; import { Trans } from '@lingui/macro'; -import { useGetGatewayTransactions } from '../../hooks'; - import { AmountLabel, Chain } from '@/components'; import { L2_CHAIN } from '@/constants'; +import { useGetGatewayTransactions } from '@/hooks'; import { InitGatewayTransaction } from '@/types'; type Props = { data: InitGatewayTransaction }; diff --git a/apps/evm/src/app/[lang]/(bridge)/components/index.ts b/apps/evm/src/app/[lang]/(bridge)/components/index.ts index 8f16b3089..ae7e977d4 100644 --- a/apps/evm/src/app/[lang]/(bridge)/components/index.ts +++ b/apps/evm/src/app/[lang]/(bridge)/components/index.ts @@ -1,6 +1,5 @@ -export * from './Layout'; -export * from './TransactionList'; +export * from './BannerCarousel'; export * from './BtcTokenInput'; export * from './GatewayGasSwitch'; -export * from './TransactionModal'; export * from './GatewayTransactionDetails'; +export * from './TransactionModal'; diff --git a/apps/evm/src/app/[lang]/(bridge)/hooks/index.ts b/apps/evm/src/app/[lang]/(bridge)/hooks/index.ts index 1517f63f9..c4279eb36 100644 --- a/apps/evm/src/app/[lang]/(bridge)/hooks/index.ts +++ b/apps/evm/src/app/[lang]/(bridge)/hooks/index.ts @@ -1,4 +1,2 @@ export * from './useGateway'; export * from './useGatewayForm'; -export * from './useGetBridgeTransactions'; -export * from './useGetGatewayTransactions'; diff --git a/apps/evm/src/app/[lang]/(bridge)/stake/Strategies.tsx b/apps/evm/src/app/[lang]/(bridge)/stake/Strategies.tsx index 5b6ced7bf..983ecdae4 100644 --- a/apps/evm/src/app/[lang]/(bridge)/stake/Strategies.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/stake/Strategies.tsx @@ -1,70 +1,22 @@ 'use client'; -import { Flex } from '@gobob/ui'; -import { useStore } from '@tanstack/react-store'; -import { watchAccount } from '@wagmi/core'; -import { useEffect, useRef } from 'react'; -import { useConfig } from 'wagmi'; - -import { Layout, TransactionList } from '../components'; -import { GetGatewayTransactionsReturnType, useGetGatewayTransactions } from '../hooks'; +import { BannerCarousel } from '../components/BannerCarousel'; import { StrategiesTable } from './components'; +import { Main } from '@/components'; import { PageLangParam } from '@/i18n/withLigui'; -import { store } from '@/lib/store'; -import { GatewayTransactionType } from '@/types'; type Props = PageLangParam & { searchParams?: { receive: string }; }; -const select = (data: GetGatewayTransactionsReturnType) => - data.filter((item) => item.subType === GatewayTransactionType.STRATEGY); - function Strategies({ searchParams }: Props) { - const config = useConfig(); - - const { data: transactions, isLoading: isLoadingTransactions } = useGetGatewayTransactions({ - query: { select } - }); - - const isInitialLoading = useStore(store, (state) => state.bridge.transactions.isInitialLoading); - - const watchAccountRef = useRef<() => void>(); - - useEffect(() => { - watchAccountRef.current = watchAccount(config, { - onChange: (account) => { - if (account.address) { - store.setState((state) => ({ - ...state, - stake: { ...state.strategies, transactions: { ...state.strategies.transactions, isInitialLoading: true } } - })); - } - } - }); - - // Cleanup by calling unwatch to unsubscribe from the account change event - return () => watchAccountRef.current?.(); - }, [config]); - - useEffect(() => { - if (isInitialLoading && !isLoadingTransactions) { - store.setState((state) => ({ - ...state, - bridge: { transactions: { ...state.bridge.transactions, isInitialLoading: false } } - })); - } - }, [isInitialLoading, isLoadingTransactions]); - return ( - - - - - - +
+ + +
); } diff --git a/apps/evm/src/app/[lang]/(bridge)/stake/[slug]/Strategy.tsx b/apps/evm/src/app/[lang]/(bridge)/stake/[slug]/Strategy.tsx index 6d557f543..6aa6e3213 100644 --- a/apps/evm/src/app/[lang]/(bridge)/stake/[slug]/Strategy.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/stake/[slug]/Strategy.tsx @@ -4,13 +4,13 @@ import { Alert, ArrowLeft, Avatar, Button, Card, Flex, H1, H2, Link, P, Skeleton import { Trans } from '@lingui/macro'; import { useState } from 'react'; -import { useGetGatewayTransactions } from '../../hooks'; import { StrategyDetails, StrategyForm } from '../components'; import { useGetStrategies } from '../hooks'; import { Layout, Main } from '@/components'; import { RoutesPath } from '@/constants'; import { PageLangParam } from '@/i18n/withLigui'; +import { useGetGatewayTransactions } from '@/hooks'; type Props = PageLangParam & { params: { slug: string }; @@ -22,7 +22,8 @@ enum Tab { } function Strategy({ params }: Props) { - const { refetch: refetchTransactions } = useGetGatewayTransactions({}); + const { refetch: refetchTransactions } = useGetGatewayTransactions(); + const [tab, setTab] = useState(Tab.Deposit); const { data: strategies = [] } = useGetStrategies(); diff --git a/apps/evm/src/app/[lang]/(bridge)/stake/components/StrategiesTable/StrategiesTable.tsx b/apps/evm/src/app/[lang]/(bridge)/stake/components/StrategiesTable/StrategiesTable.tsx index a821af555..26b06cf1f 100644 --- a/apps/evm/src/app/[lang]/(bridge)/stake/components/StrategiesTable/StrategiesTable.tsx +++ b/apps/evm/src/app/[lang]/(bridge)/stake/components/StrategiesTable/StrategiesTable.tsx @@ -1,5 +1,6 @@ import { Avatar, + Button, Card, Dd, Dl, @@ -12,6 +13,7 @@ import { P, Selection, Skeleton, + SolidClock, Span, Table, Tooltip, @@ -34,6 +36,7 @@ import { StrategiesCategories } from './StrategiesCategories'; import { AmountLabel } from '@/components'; import { RoutesPath } from '@/constants'; import { useUserAgent } from '@/user-agent'; +import { SharedStoreProfileTxType, store } from '@/lib/store'; const getSkeletons = () => Array(8) @@ -219,6 +222,26 @@ const StrategiesTable = ({ searchParams }: StrategiesTableProps) => { handleStrategyNavigate(slug as string); }; + const handlePressActivity = () => { + store.setState((state) => ({ + ...state, + shared: { + ...state.shared, + profile: { + ...state.shared.profile, + isOpen: true, + selectedTab: 'activity', + transactions: { + filters: { + ...state.shared.profile.transactions.filters, + type: SharedStoreProfileTxType.STRATEGIES + } + } + } + } + })); + }; + const columns = useMemo( () => filter === StrategiesFilterOption.MyDeposits @@ -247,10 +270,17 @@ const StrategiesTable = ({ searchParams }: StrategiesTableProps) => { ); return ( - + - + + + Activity}> + + + {isMobile ? ( { const [isOpen, setOpen] = useState(false); @@ -147,6 +146,7 @@ export function NestedProviders({ children }: PropsWithChildren) {
{children} +