mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
move rewards nav link to separate component
This commit is contained in:
@@ -4,7 +4,6 @@ import React from 'react';
|
||||
import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation';
|
||||
|
||||
import config from 'configs/app';
|
||||
import { useRewardsContext } from 'lib/contexts/rewards';
|
||||
import { rightLineArrow } from 'lib/html-entities';
|
||||
|
||||
interface ReturnType {
|
||||
@@ -17,19 +16,12 @@ export function isGroupItem(item: NavItem | NavGroupItem): item is NavGroupItem
|
||||
}
|
||||
|
||||
export function isInternalItem(item: NavItem): item is NavItemInternal {
|
||||
return !('url' in item);
|
||||
return 'nextRoute' in item;
|
||||
}
|
||||
|
||||
export default function useNavItems(): ReturnType {
|
||||
const router = useRouter();
|
||||
const pathname = router.pathname;
|
||||
const {
|
||||
openLoginModal: openRewardsLoginModal,
|
||||
balancesQuery: rewardsBalancesQuery,
|
||||
dailyRewardQuery,
|
||||
apiToken: rewardsApiToken,
|
||||
isInitialized: isRewardsInitialized,
|
||||
} = useRewardsContext();
|
||||
|
||||
return React.useMemo(() => {
|
||||
let blockchainNavItems: Array<NavItem> | Array<Array<NavItem>> = [];
|
||||
@@ -286,14 +278,6 @@ export default function useNavItems(): ReturnType {
|
||||
].filter(Boolean);
|
||||
|
||||
const accountNavItems: ReturnType['accountNavItems'] = [
|
||||
config.features.rewards.isEnabled ? {
|
||||
text: rewardsBalancesQuery.data?.total ? `${ rewardsBalancesQuery.data?.total } Merits` : 'Merits',
|
||||
nextRoute: { pathname: '/account/rewards' as const },
|
||||
onClick: (isRewardsInitialized && !rewardsApiToken) ? openRewardsLoginModal : undefined,
|
||||
icon: dailyRewardQuery.data?.available ? 'merits_with_dot' : 'merits',
|
||||
isActive: pathname === '/account/rewards',
|
||||
isDisabled: !isRewardsInitialized,
|
||||
} : null,
|
||||
{
|
||||
text: 'Watch list',
|
||||
nextRoute: { pathname: '/account/watchlist' as const },
|
||||
@@ -327,5 +311,5 @@ export default function useNavItems(): ReturnType {
|
||||
].filter(Boolean);
|
||||
|
||||
return { mainNavItems, accountNavItems };
|
||||
}, [ pathname, openRewardsLoginModal, rewardsBalancesQuery, dailyRewardQuery, rewardsApiToken, isRewardsInitialized ]);
|
||||
}, [ pathname ]);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ type NavItemCommon = {
|
||||
export type NavItemInternal = NavItemCommon & {
|
||||
nextRoute: Route;
|
||||
isActive?: boolean;
|
||||
onClick?: () => void;
|
||||
isDisabled?: boolean;
|
||||
}
|
||||
|
||||
export type NavItemExternal = {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Link, Text, HStack, Tooltip, Box, useBreakpointValue } from '@chakra-ui/react';
|
||||
import NextLink from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import type { NavItem } from 'types/client/navigation';
|
||||
|
||||
import { route } from 'nextjs-routes';
|
||||
import type { Route } from 'nextjs-routes';
|
||||
|
||||
import { useRewardsContext } from 'lib/contexts/rewards';
|
||||
import useIsMobile from 'lib/hooks/useIsMobile';
|
||||
import LightningLabel, { LIGHTNING_LABEL_CLASS_NAME } from 'ui/snippets/navigation/LightningLabel';
|
||||
import NavLinkIcon from 'ui/snippets/navigation/NavLinkIcon';
|
||||
import useColors from 'ui/snippets/navigation/useColors';
|
||||
import useNavLinkStyleProps from 'ui/snippets/navigation/useNavLinkStyleProps';
|
||||
import { checkRouteHighlight } from 'ui/snippets/navigation/utils';
|
||||
|
||||
type Props = {
|
||||
isCollapsed?: boolean;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const RewardsNavLink = ({ isCollapsed, onClick }: Props) => {
|
||||
const isMobile = useIsMobile();
|
||||
const colors = useColors();
|
||||
const router = useRouter();
|
||||
const { openLoginModal, balancesQuery, dailyRewardQuery, apiToken, isInitialized } = useRewardsContext();
|
||||
|
||||
const pathname = '/account/rewards';
|
||||
const nextRoute = { pathname } as Route;
|
||||
|
||||
const isActive = router.pathname === pathname;
|
||||
const isExpanded = isCollapsed === false;
|
||||
const styleProps = useNavLinkStyleProps({ isCollapsed, isExpanded, isActive });
|
||||
const isXLScreen = useBreakpointValue({ base: false, xl: true });
|
||||
const isHighlighted = checkRouteHighlight({ nextRoute } as NavItem);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (isInitialized && !apiToken) {
|
||||
openLoginModal();
|
||||
}
|
||||
onClick?.();
|
||||
}, [ onClick, isInitialized, apiToken, openLoginModal ]);
|
||||
|
||||
const content = (
|
||||
<Link
|
||||
href={ isInitialized && apiToken ? route(nextRoute) : undefined }
|
||||
as={ isInitialized && apiToken ? 'a' : 'button' }
|
||||
onClick={ handleClick }
|
||||
{ ...styleProps.itemProps }
|
||||
w={{ base: '100%', lg: isExpanded ? '100%' : '60px', xl: isCollapsed ? '60px' : '100%' }}
|
||||
display="flex"
|
||||
position="relative"
|
||||
px={{ base: 2, lg: isExpanded ? 2 : '15px', xl: isCollapsed ? '15px' : 2 }}
|
||||
aria-label="Merits link"
|
||||
whiteSpace="nowrap"
|
||||
_hover={{
|
||||
[`& *:not(.${ LIGHTNING_LABEL_CLASS_NAME }, .${ LIGHTNING_LABEL_CLASS_NAME } *)`]: {
|
||||
color: isInitialized ? 'link_hovered' : 'inherit',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
label="Merits"
|
||||
hasArrow={ false }
|
||||
isDisabled={ isMobile || isCollapsed === false || (isCollapsed === undefined && isXLScreen) }
|
||||
placement="right"
|
||||
variant="nav"
|
||||
gutter={ 20 }
|
||||
color={ isActive ? colors.text.active : colors.text.hover }
|
||||
margin={ 0 }
|
||||
>
|
||||
<HStack spacing={ 0 } overflow="hidden">
|
||||
<NavLinkIcon item={{ icon: dailyRewardQuery.data?.available ? 'merits_with_dot' : 'merits' } as NavItem}/>
|
||||
<Text { ...styleProps.textProps } as="span" ml={ 3 }>
|
||||
<span>
|
||||
{ balancesQuery.data?.total ? `${ balancesQuery.data?.total } Merits` : 'Merits' }
|
||||
</span>
|
||||
</Text>
|
||||
{ isHighlighted && (
|
||||
<LightningLabel iconColor={ styleProps.itemProps.bgColor } isCollapsed={ isCollapsed }/>
|
||||
) }
|
||||
</HStack>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
);
|
||||
|
||||
return (
|
||||
<Box as="li" listStyleType="none" w="100%">
|
||||
{ isInitialized && apiToken ? (
|
||||
<NextLink href={ nextRoute } passHref legacyBehavior>
|
||||
{ content }
|
||||
</NextLink>
|
||||
) : content }
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(RewardsNavLink);
|
||||
@@ -3,6 +3,7 @@ import { animate, motion, useMotionValue } from 'framer-motion';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems';
|
||||
import RewardsNavLink from 'ui/rewards/RewardsNavLink';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
import useIsAuth from 'ui/snippets/auth/useIsAuth';
|
||||
|
||||
@@ -82,6 +83,7 @@ const NavigationMobile = ({ onNavLinkClick, isMarketplaceAppPage }: Props) => {
|
||||
borderColor="divider"
|
||||
>
|
||||
<VStack as="ul" spacing="1" alignItems="flex-start">
|
||||
<RewardsNavLink onClick={ onNavLinkClick } isCollapsed={ isCollapsed }/>
|
||||
{ accountNavItems.map((item) => <NavLink key={ item.text } item={ item } onClick={ onNavLinkClick } isCollapsed={ isCollapsed }/>) }
|
||||
</VStack>
|
||||
</Box>
|
||||
|
||||
@@ -7,5 +7,5 @@ export function checkRouteHighlight(item: NavItem | Array<NavItem> | Array<Array
|
||||
if (Array.isArray(item)) {
|
||||
return item.some((subItem) => checkRouteHighlight(subItem));
|
||||
}
|
||||
return isInternalItem(item) && item.nextRoute !== undefined && (config.UI.navigation.highlightedRoutes.includes(item.nextRoute.pathname));
|
||||
return isInternalItem(item) && (config.UI.navigation.highlightedRoutes.includes(item.nextRoute.pathname));
|
||||
}
|
||||
|
||||
@@ -34,19 +34,13 @@ const NavLink = ({ item, isCollapsed, px, className, onClick, disableActiveState
|
||||
|
||||
const styleProps = useNavLinkStyleProps({ isCollapsed, isExpanded, isActive: isInternalLink && item.isActive && !disableActiveState });
|
||||
const isXLScreen = useBreakpointValue({ base: false, xl: true });
|
||||
let href;
|
||||
if (isInternalLink && !item.onClick) {
|
||||
href = route(item.nextRoute);
|
||||
} else if ('url' in item) {
|
||||
href = item.url;
|
||||
}
|
||||
const href = isInternalLink ? route(item.nextRoute) : item.url;
|
||||
|
||||
const isHighlighted = checkRouteHighlight(item);
|
||||
const isDisabled = isInternalLink && item.isDisabled;
|
||||
|
||||
const content = (
|
||||
<Link
|
||||
href={ isDisabled ? undefined : href }
|
||||
href={ href }
|
||||
target={ isInternalLink ? '_self' : '_blank' }
|
||||
{ ...styleProps.itemProps }
|
||||
w={{ base: '100%', lg: isExpanded ? '100%' : '60px', xl: isCollapsed ? '60px' : '100%' }}
|
||||
@@ -55,11 +49,10 @@ const NavLink = ({ item, isCollapsed, px, className, onClick, disableActiveState
|
||||
px={ px || { base: 2, lg: isExpanded ? 2 : '15px', xl: isCollapsed ? '15px' : 2 } }
|
||||
aria-label={ `${ item.text } link` }
|
||||
whiteSpace="nowrap"
|
||||
as={ isInternalLink && item.onClick ? 'button' : 'a' }
|
||||
onClick={ isInternalLink && item.onClick ? item.onClick : onClick }
|
||||
onClick={ onClick }
|
||||
_hover={{
|
||||
[`& *:not(.${ LIGHTNING_LABEL_CLASS_NAME }, .${ LIGHTNING_LABEL_CLASS_NAME } *)`]: {
|
||||
color: isDisabled ? 'inherit' : 'link_hovered',
|
||||
color: 'link_hovered',
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -89,7 +82,7 @@ const NavLink = ({ item, isCollapsed, px, className, onClick, disableActiveState
|
||||
|
||||
return (
|
||||
<Box as="li" listStyleType="none" w="100%" className={ className }>
|
||||
{ isInternalLink && !item.onClick && !isDisabled ? (
|
||||
{ isInternalLink ? (
|
||||
<NextLink href={ item.nextRoute } passHref legacyBehavior>
|
||||
{ content }
|
||||
</NextLink>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useAppContext } from 'lib/contexts/app';
|
||||
import * as cookies from 'lib/cookies';
|
||||
import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems';
|
||||
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
|
||||
import RewardsNavLink from 'ui/rewards/RewardsNavLink';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
import useIsAuth from 'ui/snippets/auth/useIsAuth';
|
||||
import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo';
|
||||
@@ -100,6 +101,7 @@ const NavigationDesktop = () => {
|
||||
{ isAuth && (
|
||||
<Box as="nav" borderTopWidth="1px" borderColor="divider" w="100%" mt={ 3 } pt={ 3 }>
|
||||
<VStack as="ul" spacing="1" alignItems="flex-start">
|
||||
<RewardsNavLink isCollapsed={ isCollapsed }/>
|
||||
{ accountNavItems.map((item) => <NavLink key={ item.text } item={ item } isCollapsed={ isCollapsed }/>) }
|
||||
</VStack>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user