Skip to content

Commit

Permalink
feat: new tx history layout (#2072)
Browse files Browse the repository at this point in the history
  • Loading branch information
fionnachan authored Nov 29, 2024
1 parent 586e2f8 commit fcecf30
Show file tree
Hide file tree
Showing 31 changed files with 409 additions and 398 deletions.
5 changes: 5 additions & 0 deletions packages/arb-token-bridge-ui/public/icons/history.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/arb-token-bridge-ui/public/icons/wallet.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 2 additions & 24 deletions packages/arb-token-bridge-ui/src/components/App/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ type AppContextState = {
layout: {
isTransferPanelVisible: boolean
isTransferring: boolean
isTransactionHistoryPanelVisible: boolean
}
}

const initialState: AppContextState = {
layout: {
isTransferPanelVisible: true,
isTransferring: false,
isTransactionHistoryPanelVisible: false
isTransferring: false
}
}

Expand All @@ -29,7 +27,6 @@ const AppContext = createContext<AppContextValue>([initialState, () => {}])
type Action =
| { type: 'layout.set_is_transfer_panel_visible'; payload: boolean }
| { type: 'layout.set_is_transferring'; payload: boolean }
| { type: 'layout.set_txhistory_panel_visible'; payload: boolean }

function reducer(state: AppContextState, action: Action) {
switch (action.type) {
Expand All @@ -39,15 +36,6 @@ function reducer(state: AppContextState, action: Action) {
layout: { ...state.layout, isTransferPanelVisible: action.payload }
}

case 'layout.set_txhistory_panel_visible':
return {
...state,
layout: {
...state.layout,
isTransactionHistoryPanelVisible: action.payload
}
}

case 'layout.set_is_transferring':
return {
...state,
Expand Down Expand Up @@ -88,17 +76,7 @@ export const useAppContextActions = (dispatchOverride?: Dispatch<Action>) => {
dispatch({ type: 'layout.set_is_transferring', payload })
}

const openTransactionHistoryPanel = () => {
dispatch({ type: 'layout.set_txhistory_panel_visible', payload: true })
}

const closeTransactionHistoryPanel = () => {
dispatch({ type: 'layout.set_txhistory_panel_visible', payload: false })
}

return {
setTransferring,
openTransactionHistoryPanel,
closeTransactionHistoryPanel
setTransferring
}
}
Original file line number Diff line number Diff line change
@@ -1,68 +1,54 @@
import { useEffect, useMemo } from 'react'
import { useAccount } from 'wagmi'
import { useLocalStorage } from '@uidotdev/usehooks'
import { Tab } from '@headlessui/react'
import { create } from 'zustand'

import { TransferPanel } from '../TransferPanel/TransferPanel'
import { SidePanel } from '../common/SidePanel'
import { useAppContextActions, useAppContextState } from '../App/AppContext'
import { ArbitrumStats, statsLocalStorageKey } from './ArbitrumStats'
import { SettingsDialog } from '../common/SettingsDialog'
import { TransactionHistory } from '../TransactionHistory/TransactionHistory'
import { useTransactionHistory } from '../../hooks/useTransactionHistory'
import { isTxPending } from '../TransactionHistory/helpers'
import { TransactionStatusInfo } from '../TransactionHistory/TransactionStatusInfo'
import { TopNavBar } from '../TopNavBar'

function TransactionHistorySidePanel() {
const { closeTransactionHistoryPanel } = useAppContextActions()
const {
layout: { isTransactionHistoryPanelVisible }
} = useAppContextState()
const { address } = useAccount()

const transactionHistoryProps = useTransactionHistory(address, {
runFetcher: true
})

const { transactions, updatePendingTransaction } = transactionHistoryProps

const pendingTransactions = useMemo(() => {
return transactions.filter(isTxPending)
}, [transactions])

useEffect(() => {
const interval = setInterval(() => {
pendingTransactions.forEach(updatePendingTransaction)
}, 10_000)

return () => clearInterval(interval)
}, [pendingTransactions, updatePendingTransaction])
enum MainContentTabs {
Bridge = 0,
TransactionHistory = 1
}

return (
<SidePanel
isOpen={isTransactionHistoryPanelVisible}
onClose={closeTransactionHistoryPanel}
scrollable={false}
panelClassNameOverrides="pb-8"
>
<TransactionHistory props={{ ...transactionHistoryProps, address }} />
</SidePanel>
)
type MainContentTabStore = {
selectedTab: MainContentTabs
setSelectedTab: (index: MainContentTabs) => void
switchToBridgeTab: () => void
switchToTransactionHistoryTab: () => void
}

export const useMainContentTabs = create<MainContentTabStore>(set => ({
selectedTab: MainContentTabs.Bridge,
setSelectedTab: (index: MainContentTabs) => set({ selectedTab: index }),
switchToBridgeTab: () => set({ selectedTab: MainContentTabs.Bridge }),
switchToTransactionHistoryTab: () =>
set({ selectedTab: MainContentTabs.TransactionHistory })
}))

export function MainContent() {
const [isArbitrumStatsVisible] =
useLocalStorage<boolean>(statsLocalStorageKey)
const { selectedTab, setSelectedTab } = useMainContentTabs()

return (
<>
<div className="main-panel mx-auto flex w-full flex-col sm:max-w-[600px] sm:pb-12 sm:pt-6">
<TransactionStatusInfo />

<TransferPanel />
<div className="main-panel mx-auto flex w-full flex-col items-center gap-3 sm:pt-6">
<Tab.Group selectedIndex={selectedTab} onChange={setSelectedTab}>
<TopNavBar />
<Tab.Panels className="flex w-full items-center justify-center">
<Tab.Panel className="w-full sm:max-w-[600px]">
<TransferPanel />
</Tab.Panel>
<Tab.Panel className="w-full md:px-4">
<TransactionHistory />
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
</div>

<TransactionHistorySidePanel />

{/* Settings panel */}
<SettingsDialog />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export const AccountMenuItem = () => {
accountShort,
ensName,
ensAvatar,
openTransactionHistory,
disconnect,
udInfo,
chain,
Expand All @@ -36,12 +35,6 @@ export const AccountMenuItem = () => {
/>
}
>
<MenuItem
title="Transactions"
Icon={<DocumentTextIcon className="h-[18px] w-[18px]" />}
onClick={openTransactionHistory}
isMobile
/>
{chain && (
<MenuItem
title="Explorer"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const DynamicSidebar = dynamic(
export const AppSidebar = () => {
const posthog = usePostHog()
return (
<div className="sticky top-0 z-20 hidden h-full font-normal sm:flex">
<div className="sticky left-0 top-0 z-20 hidden h-full font-normal sm:flex">
<DynamicSidebar logger={posthog} activeMenu="Bridge" />
</div>
)
Expand Down
48 changes: 48 additions & 0 deletions packages/arb-token-bridge-ui/src/components/TopNavBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Tab } from '@headlessui/react'
import { PaperAirplaneIcon } from '@heroicons/react/24/outline'
import { PropsWithChildren } from 'react'
import { twMerge } from 'tailwind-merge'
import Image from 'next/image'
import { useTransactionReminderInfo } from './TransactionHistory/useTransactionReminderInfo'

function StyledTab({ children, ...props }: PropsWithChildren) {
return (
<Tab
className="flex h-full items-center justify-center gap-2 rounded p-1 text-lg ui-selected:bg-black/75"
{...props}
>
{children}
</Tab>
)
}

StyledTab.displayName = 'StyledTab'

export function TopNavBar() {
const { colorClassName } = useTransactionReminderInfo()

return (
<Tab.List
className={twMerge(
'grid w-full max-w-[600px] grid-cols-2 bg-white/20 p-[8px] text-white md:rounded'
)}
>
<StyledTab aria-label="Switch to Bridge Tab">
<PaperAirplaneIcon className="h-3 w-3" />
Bridge
</StyledTab>
<StyledTab aria-label="Switch to Transaction History Tab">
<Image
src="/icons/history.svg"
width={24}
height={24}
alt="history icon"
/>
Txn History{' '}
<span
className={twMerge('h-3 w-3 rounded-full', colorClassName.light)}
/>
</StyledTab>
</Tab.List>
)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import dayjs from 'dayjs'
import { useMemo } from 'react'
import { useEffect, useMemo } from 'react'
import { Tab } from '@headlessui/react'
import { create } from 'zustand'
import { useAccount } from 'wagmi'

import { UseTransactionHistoryResult } from '../../hooks/useTransactionHistory'
import { TransactionHistoryTable } from './TransactionHistoryTable'
import { TransactionStatusInfo } from '../TransactionHistory/TransactionStatusInfo'
import {
isTxClaimable,
isTxCompleted,
Expand All @@ -15,7 +16,31 @@ import {
import { MergedTransaction } from '../../state/app/state'
import { TabButton } from '../common/Tab'
import { TransactionsTableDetails } from './TransactionsTableDetails'
import { Address } from '../../util/AddressUtils'
import { useTransactionHistory } from '../../hooks/useTransactionHistory'

function useTransactionHistoryUpdater() {
const { address } = useAccount()

const transactionHistoryProps = useTransactionHistory(address, {
runFetcher: true
})

const { transactions, updatePendingTransaction } = transactionHistoryProps

const pendingTransactions = useMemo(() => {
return transactions.filter(isTxPending)
}, [transactions])

useEffect(() => {
const interval = setInterval(() => {
pendingTransactions.forEach(updatePendingTransaction)
}, 10_000)

return () => clearInterval(interval)
}, [pendingTransactions, updatePendingTransaction])

return transactionHistoryProps
}

const tabClasses =
'text-white px-3 mr-2 border-b-2 ui-selected:border-white ui-not-selected:border-transparent ui-not-selected:text-white/80 arb-hover'
Expand Down Expand Up @@ -46,12 +71,10 @@ export const useTxDetailsStore = create<TxDetailsStore>(set => ({
reset: () => set({ tx: null })
}))

export const TransactionHistory = ({
props
}: {
props: UseTransactionHistoryResult & { address: Address | undefined }
}) => {
const { transactions, address } = props
export const TransactionHistory = () => {
const { address } = useAccount()
const props = useTransactionHistoryUpdater()
const { transactions } = props

const oldestTxTimeAgoString = useMemo(() => {
return dayjs(transactions[transactions.length - 1]?.createdAt).toNow(true)
Expand Down Expand Up @@ -94,25 +117,33 @@ export const TransactionHistory = ({
const settledTransactions = groupedTransactions.settled

return (
<>
<Tab.Group key={address} as="div" className="h-full overflow-hidden">
<div className="m-auto w-full max-w-[100vw] border-y border-white/30 bg-[#191919] py-4 pl-4 md:max-w-[1000px] md:rounded md:border-x md:pr-4">
<div className="pr-4 md:pr-0">
<TransactionStatusInfo />
</div>

<Tab.Group
key={address}
as="div"
className="h-full overflow-hidden rounded pr-4 md:pr-0"
>
<Tab.List className="mb-4 flex border-b border-white/30">
<TabButton
aria-label="show pending transactions"
className={tabClasses}
>
<span className="text-xs md:text-base">Pending transactions</span>
<span className="text-sm md:text-base">Pending transactions</span>
</TabButton>
<TabButton
aria-label="show settled transactions"
className={tabClasses}
>
<span className="text-xs md:text-base">Settled transactions</span>
<span className="text-sm md:text-base">Settled transactions</span>
</TabButton>
</Tab.List>

<Tab.Panels className="h-full overflow-hidden">
<Tab.Panel className="h-full">
<Tab.Panels className="h-full w-full overflow-hidden">
<Tab.Panel className="h-full w-full">
<TransactionHistoryTable
{...props}
address={address}
Expand All @@ -121,7 +152,7 @@ export const TransactionHistory = ({
oldestTxTimeAgoString={oldestTxTimeAgoString}
/>
</Tab.Panel>
<Tab.Panel className="h-full">
<Tab.Panel className="h-full w-full">
<TransactionHistoryTable
{...props}
address={address}
Expand All @@ -133,6 +164,6 @@ export const TransactionHistory = ({
</Tab.Panels>
</Tab.Group>
<TransactionsTableDetails address={address} />
</>
</div>
)
}
Loading

0 comments on commit fcecf30

Please sign in to comment.