diff --git a/src/renderer/src/components/ContactAddressTable/AddressCell.tsx b/src/renderer/src/components/ContactAddressTable/AddressCell.tsx index 029773fe..9a1b6a1f 100644 --- a/src/renderer/src/components/ContactAddressTable/AddressCell.tsx +++ b/src/renderer/src/components/ContactAddressTable/AddressCell.tsx @@ -25,7 +25,6 @@ export const AddressCell = ({ address, blockchain }: TContactAddress) => { } - size="sm" onClick={() => UtilsHelper.copyToClipboard(address)} /> diff --git a/src/renderer/src/components/IconButton.tsx b/src/renderer/src/components/IconButton.tsx index f5d6ca4f..7aeb5553 100644 --- a/src/renderer/src/components/IconButton.tsx +++ b/src/renderer/src/components/IconButton.tsx @@ -4,13 +4,13 @@ import { StyleHelper } from '@renderer/helpers/StyleHelper' type TProps = { icon: JSX.Element text?: string - size?: 'sm' | 'md' + size?: 'xs' | 'sm' | 'md' compacted?: boolean colorSchema?: 'neon' | 'gray' } & ComponentProps<'button'> export const IconButton = forwardRef( - ({ text, icon, size = 'sm', compacted, colorSchema = 'gray', ...props }, ref) => { + ({ text, icon, size = 'xs', compacted, colorSchema = 'gray', ...props }, ref) => { const { className: iconClassName, ...iconProps } = icon.props return ( @@ -20,8 +20,8 @@ export const IconButton = forwardRef( className={StyleHelper.mergeStyles( 'flex flex-col h-fit justify-center items-center disabled:cursor-not-allowed disabled:opacity-50 flex-grow-0 rounded transition-colors hover:enabled:bg-gray-300/15 aria-selected:bg-gray-300/15 aria-selected:hover:bg-gray-300/30 aria-expanded:bg-gray-300/15 aria-expanded:hover:bg-gray-300/30', { - 'py-1 px-2 gap-y-0.5': size === 'sm' && !compacted, - 'p-1 gap-y-0.5': size === 'sm' && compacted, + 'py-1 px-2 gap-y-0.5': (size === 'sm' || size === 'xs') && !compacted, + 'p-1 gap-y-0.5': (size === 'sm' || size === 'xs') && compacted, 'py-1.5 px-3 gap-y-1': size === 'md' && !compacted, 'p-1 gap-y-1': size === 'md' && compacted, 'text-neon ': colorSchema === 'neon', @@ -34,7 +34,8 @@ export const IconButton = forwardRef( className: StyleHelper.mergeStyles( 'object-contain ', { - 'w-4 h-4': size === 'sm', + 'w-4 h-4': size === 'xs', + 'w-5 h-5': size === 'sm', 'w-6 h-6': size === 'md', }, iconClassName diff --git a/src/renderer/src/hooks/useQuery.ts b/src/renderer/src/hooks/useQuery.ts new file mode 100644 index 00000000..3e09bfc7 --- /dev/null +++ b/src/renderer/src/hooks/useQuery.ts @@ -0,0 +1,32 @@ +import { useCallback, useSyncExternalStore } from 'react' +import { notifyManager, QueryFilters, useIsFetching, useQueryClient } from '@tanstack/react-query' + +export function useRefetch(filters?: QueryFilters) { + const queryClient = useQueryClient() + + const isRefetching = useIsFetching({ ...filters, predicate: query => query.state.status !== 'pending' }) + + const refetch = useCallback(async () => { + await queryClient.invalidateQueries({ ...filters, refetchType: 'all' }) + }, [queryClient, filters]) + + return { + refetch, + isRefetching, + } +} + +export function useLastUpdated(filters?: QueryFilters) { + const queryClient = useQueryClient() + + const queryCache = queryClient.getQueryCache() + + return useSyncExternalStore( + useCallback(onStoreChange => queryCache.subscribe(notifyManager.batchCalls(onStoreChange)), [queryCache]), + () => { + const queries = queryCache.findAll(filters) + const sortedQueries = queries.sort((a, b) => b.state.dataUpdatedAt - a.state.dataUpdatedAt) + return sortedQueries[0].state.dataUpdatedAt + } + ) +} diff --git a/src/renderer/src/locales/en/pages.json b/src/renderer/src/locales/en/pages.json index 8562ae68..2c2ef9c6 100644 --- a/src/renderer/src/locales/en/pages.json +++ b/src/renderer/src/locales/en/pages.json @@ -159,6 +159,7 @@ "newWalletButtonLabel": "New Wallet", "address": "Address", "accounts": "Accounts", + "lastUpdated": "Last updated: {{date}}", "accountNftList": { "title": "NFTs", "empty": "No NFTS to display", diff --git a/src/renderer/src/routes/pages/Wallets/index.tsx b/src/renderer/src/routes/pages/Wallets/index.tsx index 27e7a65c..24df6e70 100644 --- a/src/renderer/src/routes/pages/Wallets/index.tsx +++ b/src/renderer/src/routes/pages/Wallets/index.tsx @@ -1,7 +1,7 @@ import { Fragment, useLayoutEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { MdAdd, MdOutlineContentCopy } from 'react-icons/md' -import { TbFileImport, TbPencil } from 'react-icons/tb' +import { TbFileImport, TbPencil, TbRefresh } from 'react-icons/tb' import { Outlet, useNavigate, useParams } from 'react-router-dom' import { hasNft } from '@cityofzion/blockchain-service' import { Button } from '@renderer/components/Button' @@ -9,10 +9,12 @@ import { IconButton } from '@renderer/components/IconButton' import { Separator } from '@renderer/components/Separator' import { SidebarMenuButton } from '@renderer/components/SidebarMenuButton' import { StringHelper } from '@renderer/helpers/StringHelper' +import { StyleHelper } from '@renderer/helpers/StyleHelper' import { UtilsHelper } from '@renderer/helpers/UtilsHelper' import { WalletConnectHelper } from '@renderer/helpers/WalletConnectHelper' import { useAccountsSelector } from '@renderer/hooks/useAccountSelector' import { useModalNavigate } from '@renderer/hooks/useModalRouter' +import { useLastUpdated, useRefetch } from '@renderer/hooks/useQuery' import { useWalletsSelector } from '@renderer/hooks/useWalletSelector' import { MainLayout } from '@renderer/layouts/Main' import { bsAggregator } from '@renderer/libs/blockchainService' @@ -33,6 +35,9 @@ export const WalletsPage = () => { const navigate = useNavigate() const { id } = useParams() + const { refetch, isRefetching } = useRefetch() + const lastUpdated = useLastUpdated() + const [selectedWallet, setSelectedWallet] = useState(wallets[0]) const [selectedAccount, setSelectedAccount] = useState( accounts.find(account => account.idWallet === selectedWallet?.id) @@ -148,23 +153,39 @@ export const WalletsPage = () => {

{StringHelper.truncateStringMiddle(selectedAccount.address, 8)}

} - size="sm" colorSchema="neon" compacted onClick={() => UtilsHelper.copyToClipboard(selectedAccount.address)} /> -