Commit bb7df432 authored by tom's avatar tom

refactor routed tabs

parent f129e6d4
...@@ -4,12 +4,12 @@ import React from 'react'; ...@@ -4,12 +4,12 @@ import React from 'react';
import PageNextJs from 'nextjs/PageNextJs'; import PageNextJs from 'nextjs/PageNextJs';
// const Blocks = dynamic(() => import('ui/pages/Blocks'), { ssr: false }); const Blocks = dynamic(() => import('ui/pages/Blocks'), { ssr: false });
const Page: NextPage = () => { const Page: NextPage = () => {
return ( return (
<PageNextJs pathname="/blocks"> <PageNextJs pathname="/blocks">
{ /* <Blocks/> */ } <Blocks/>
</PageNextJs> </PageNextJs>
); );
}; };
......
...@@ -8,4 +8,10 @@ export const menuButton: TabItemMenu = { ...@@ -8,4 +8,10 @@ export const menuButton: TabItemMenu = {
component: null, component: null,
}; };
export const getTabValue = (tab: TabItem): string => tab.id.toString(); export const getTabValue = (tab: TabItem): string => {
if (Array.isArray(tab.id)) {
return tab.id[0];
}
return tab.id;
};
import { pickBy } from 'es-toolkit';
import { useRouter } from 'next/router';
import React from 'react';
import type { Props as AdaptiveTabsProps } from '../AdaptiveTabs/AdaptiveTabs';
import AdaptiveTabs from '../AdaptiveTabs/AdaptiveTabs';
import { getTabValue } from '../AdaptiveTabs/utils';
import useActiveTabFromQuery from './useActiveTabFromQuery';
interface Props extends AdaptiveTabsProps {}
const RoutedTabs = (props: Props) => {
const { tabs, onValueChange, ...rest } = props;
const router = useRouter();
const activeTab = useActiveTabFromQuery(props.tabs);
const tabsRef = React.useRef<HTMLDivElement>(null);
const handleValueChange = React.useCallback(({ value }: { value: string }) => {
const nextTab = tabs.find((tab) => getTabValue(tab) === value);
if (!nextTab) {
return;
}
const queryForPathname = pickBy(router.query, (value, key) => router.pathname.includes(`[${ key }]`));
router.push(
{ pathname: router.pathname, query: { ...queryForPathname, tab: value } },
undefined,
{ shallow: true },
);
onValueChange?.({ value });
}, [ tabs, router, onValueChange ]);
React.useEffect(() => {
if (router.query.scroll_to_tabs) {
tabsRef?.current?.scrollIntoView(true);
delete router.query.scroll_to_tabs;
router.push(
{
pathname: router.pathname,
query: router.query,
},
undefined,
{ shallow: true },
);
}
// replicate componentDidMount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<AdaptiveTabs
{ ...rest }
tabs={ tabs }
onValueChange={ handleValueChange }
defaultValue={ activeTab ? getTabValue(activeTab) : undefined }
/>
);
};
export default React.memo(RoutedTabs);
import { useRouter } from 'next/router';
import type { TabItem } from '../AdaptiveTabs/types';
import getQueryParamString from 'lib/router/getQueryParamString';
export default function useActiveTabFromQuery(tabs: Array<TabItem>) {
const router = useRouter();
const tabFromQuery = getQueryParamString(router.query.tab);
if (!tabFromQuery) {
return;
}
return tabs.find((tab) => {
if (Array.isArray(tab.id)) {
return tab.id.includes(tabFromQuery);
}
return tab.id === tabFromQuery || ('subTabs' in tab && tab.subTabs?.some((id) => id === tabFromQuery));
});
}
...@@ -15,6 +15,7 @@ export const recipe = defineSlotRecipe({ ...@@ -15,6 +15,7 @@ export const recipe = defineSlotRecipe({
}, },
list: { list: {
display: 'inline-flex', display: 'inline-flex',
width: '100%',
position: 'relative', position: 'relative',
isolation: 'isolate', isolation: 'isolate',
'--tabs-indicator-shadow': 'shadows.xs', '--tabs-indicator-shadow': 'shadows.xs',
......
...@@ -2,20 +2,16 @@ import React from 'react'; ...@@ -2,20 +2,16 @@ import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import { Heading } from 'toolkit/chakra/heading'; import { Heading } from 'toolkit/chakra/heading';
import AdaptiveTabs from 'toolkit/components/AdaptiveTabs/AdaptiveTabs';
import LatestOptimisticDeposits from 'ui/home/latestDeposits/LatestOptimisticDeposits'; import LatestOptimisticDeposits from 'ui/home/latestDeposits/LatestOptimisticDeposits';
import LatestTxs from 'ui/home/LatestTxs'; import LatestTxs from 'ui/home/LatestTxs';
import LatestWatchlistTxs from 'ui/home/LatestWatchlistTxs'; import LatestWatchlistTxs from 'ui/home/LatestWatchlistTxs';
import TabsWithScroll from 'ui/shared/Tabs/TabsWithScroll';
import useAuth from 'ui/snippets/auth/useIsAuth'; import useAuth from 'ui/snippets/auth/useIsAuth';
import LatestArbitrumDeposits from './latestDeposits/LatestArbitrumDeposits'; import LatestArbitrumDeposits from './latestDeposits/LatestArbitrumDeposits';
const rollupFeature = config.features.rollup; const rollupFeature = config.features.rollup;
const TAB_LIST_PROPS = {
mb: { base: 3, lg: 3 },
};
const TransactionsHome = () => { const TransactionsHome = () => {
const isAuth = useAuth(); const isAuth = useAuth();
if ((rollupFeature.isEnabled && (rollupFeature.type === 'optimistic' || rollupFeature.type === 'arbitrum')) || isAuth) { if ((rollupFeature.isEnabled && (rollupFeature.type === 'optimistic' || rollupFeature.type === 'arbitrum')) || isAuth) {
...@@ -30,7 +26,7 @@ const TransactionsHome = () => { ...@@ -30,7 +26,7 @@ const TransactionsHome = () => {
return ( return (
<> <>
<Heading level="3" mb={ 3 }>Transactions</Heading> <Heading level="3" mb={ 3 }>Transactions</Heading>
<TabsWithScroll tabs={ tabs } lazyBehavior="keepMounted" tabListProps={ TAB_LIST_PROPS }/> <AdaptiveTabs tabs={ tabs } unmountOnExit={ false } listProps={{ mb: 3 }}/>
</> </>
); );
} }
......
...@@ -7,11 +7,11 @@ import useIsMobile from 'lib/hooks/useIsMobile'; ...@@ -7,11 +7,11 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import { BLOCK } from 'stubs/block'; import { BLOCK } from 'stubs/block';
import { generateListStub } from 'stubs/utils'; import { generateListStub } from 'stubs/utils';
import RoutedTabs from 'toolkit/components/RoutedTabs/RoutedTabs';
import BlocksContent from 'ui/blocks/BlocksContent'; import BlocksContent from 'ui/blocks/BlocksContent';
import BlocksTabSlot from 'ui/blocks/BlocksTabSlot'; import BlocksTabSlot from 'ui/blocks/BlocksTabSlot';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
const TAB_LIST_PROPS = { const TAB_LIST_PROPS = {
marginBottom: 0, marginBottom: 0,
...@@ -70,17 +70,22 @@ const BlocksPageContent = () => { ...@@ -70,17 +70,22 @@ const BlocksPageContent = () => {
})(); })();
const tabs: Array<RoutedTab> = [ const tabs: Array<RoutedTab> = [
{ id: 'blocks', title: 'All', component: <BlocksContent type="block" query={ blocksQuery }/> }, { id: 'blocks', title: 'All', component: <div>All</div> },
{ id: 'reorgs', title: 'Forked', component: <BlocksContent type="reorg" query={ reorgsQuery }/> }, { id: 'reorgs', title: 'Forked', component: <div>Forked</div> },
{ id: 'uncles', title: 'Uncles', component: <BlocksContent type="uncle" query={ unclesQuery }/> }, { id: 'uncles', title: 'Uncles', component: <div>Uncles</div> },
]; ];
// const tabs: Array<RoutedTab> = [
// { id: 'blocks', title: 'All', component: <BlocksContent type="block" query={ blocksQuery }/> },
// { id: 'reorgs', title: 'Forked', component: <BlocksContent type="reorg" query={ reorgsQuery }/> },
// { id: 'uncles', title: 'Uncles', component: <BlocksContent type="uncle" query={ unclesQuery }/> },
// ];
return ( return (
<> <>
<PageTitle title="Blocks" withTextAd/> <PageTitle title="Blocks" withTextAd/>
<RoutedTabs <RoutedTabs
tabs={ tabs } tabs={ tabs }
tabListProps={ isMobile ? undefined : TAB_LIST_PROPS } listProps={ isMobile ? undefined : TAB_LIST_PROPS }
rightSlot={ <BlocksTabSlot pagination={ pagination }/> } rightSlot={ <BlocksTabSlot pagination={ pagination }/> }
stickyEnabled={ !isMobile } stickyEnabled={ !isMobile }
/> />
......
import { Image, chakra } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { HOMEPAGE_STATS } from 'stubs/stats'; import { HOMEPAGE_STATS } from 'stubs/stats';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Image } from 'toolkit/chakra/image';
import { Skeleton } from 'toolkit/chakra/skeleton';
import TokenLogoPlaceholder from './TokenLogoPlaceholder'; import TokenLogoPlaceholder from './TokenLogoPlaceholder';
...@@ -23,7 +24,7 @@ const NativeTokenIcon = ({ isLoading, className, type }: Props) => { ...@@ -23,7 +24,7 @@ const NativeTokenIcon = ({ isLoading, className, type }: Props) => {
}); });
if (isLoading || statsQueryResult.isPlaceholderData) { if (isLoading || statsQueryResult.isPlaceholderData) {
return <Skeleton borderRadius="base" className={ className }/>; return <Skeleton borderRadius="base" loading className={ className }/>;
} }
const src = type === 'secondary' ? statsQueryResult.data?.secondary_coin_image : statsQueryResult.data?.coin_image; const src = type === 'secondary' ? statsQueryResult.data?.secondary_coin_image : statsQueryResult.data?.coin_image;
...@@ -32,10 +33,10 @@ const NativeTokenIcon = ({ isLoading, className, type }: Props) => { ...@@ -32,10 +33,10 @@ const NativeTokenIcon = ({ isLoading, className, type }: Props) => {
<Image <Image
borderRadius="base" borderRadius="base"
className={ className } className={ className }
src={ src || '' } src={ src || undefined }
alt={ `${ config.chain.currency.symbol } logo` } alt={ `${ config.chain.currency.symbol } logo` }
fallback={ <TokenLogoPlaceholder borderRadius="base" className={ className }/> } fallback={ <TokenLogoPlaceholder borderRadius="base" className={ className }/> }
fallbackStrategy={ src ? 'onError' : 'beforeLoadOrError' } // fallbackStrategy={ src ? 'onError' : 'beforeLoadOrError' }
/> />
); );
}; };
......
...@@ -4,10 +4,10 @@ import React from 'react'; ...@@ -4,10 +4,10 @@ import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { Heading } from 'toolkit/chakra/heading'; import { Heading } from 'toolkit/chakra/heading';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tooltip } from 'toolkit/chakra/tooltip'; import { Tooltip } from 'toolkit/chakra/tooltip';
import { useDisclosure } from 'toolkit/hooks/useDisclosure'; import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import TextAd from 'ui/shared/ad/TextAd'; import TextAd from 'ui/shared/ad/TextAd';
import Skeleton from 'ui/shared/chakra/Skeleton';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal'; import LinkInternal from 'ui/shared/links/LinkInternal';
...@@ -42,7 +42,7 @@ const BackLink = (props: BackLinkProp & { isLoading?: boolean }) => { ...@@ -42,7 +42,7 @@ const BackLink = (props: BackLinkProp & { isLoading?: boolean }) => {
mr={ 3 } mr={ 3 }
my={ 2 } my={ 2 }
verticalAlign="text-bottom" verticalAlign="text-bottom"
loading={ props.isLoading } loading
/> />
); );
} }
...@@ -139,7 +139,6 @@ const PageTitle = ({ title, contentAfter, withTextAd, backLink, className, isLoa ...@@ -139,7 +139,6 @@ const PageTitle = ({ title, contentAfter, withTextAd, backLink, className, isLoa
> >
<Heading <Heading
ref={ headingRef } ref={ headingRef }
as="h1"
level="1" level="1"
whiteSpace="normal" whiteSpace="normal"
wordBreak="break-all" wordBreak="break-all"
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment