Commit b472070b authored by Max Alekseenko's avatar Max Alekseenko

move rewards nav link to separate component

parent 201be844
...@@ -4,7 +4,6 @@ import React from 'react'; ...@@ -4,7 +4,6 @@ import React from 'react';
import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation'; import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation';
import config from 'configs/app'; import config from 'configs/app';
import { useRewardsContext } from 'lib/contexts/rewards';
import { rightLineArrow } from 'lib/html-entities'; import { rightLineArrow } from 'lib/html-entities';
interface ReturnType { interface ReturnType {
...@@ -17,19 +16,12 @@ export function isGroupItem(item: NavItem | NavGroupItem): item is NavGroupItem ...@@ -17,19 +16,12 @@ export function isGroupItem(item: NavItem | NavGroupItem): item is NavGroupItem
} }
export function isInternalItem(item: NavItem): item is NavItemInternal { export function isInternalItem(item: NavItem): item is NavItemInternal {
return !('url' in item); return 'nextRoute' in item;
} }
export default function useNavItems(): ReturnType { export default function useNavItems(): ReturnType {
const router = useRouter(); const router = useRouter();
const pathname = router.pathname; const pathname = router.pathname;
const {
openLoginModal: openRewardsLoginModal,
balancesQuery: rewardsBalancesQuery,
dailyRewardQuery,
apiToken: rewardsApiToken,
isInitialized: isRewardsInitialized,
} = useRewardsContext();
return React.useMemo(() => { return React.useMemo(() => {
let blockchainNavItems: Array<NavItem> | Array<Array<NavItem>> = []; let blockchainNavItems: Array<NavItem> | Array<Array<NavItem>> = [];
...@@ -286,14 +278,6 @@ export default function useNavItems(): ReturnType { ...@@ -286,14 +278,6 @@ export default function useNavItems(): ReturnType {
].filter(Boolean); ].filter(Boolean);
const accountNavItems: ReturnType['accountNavItems'] = [ 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', text: 'Watch list',
nextRoute: { pathname: '/account/watchlist' as const }, nextRoute: { pathname: '/account/watchlist' as const },
...@@ -327,5 +311,5 @@ export default function useNavItems(): ReturnType { ...@@ -327,5 +311,5 @@ export default function useNavItems(): ReturnType {
].filter(Boolean); ].filter(Boolean);
return { mainNavItems, accountNavItems }; return { mainNavItems, accountNavItems };
}, [ pathname, openRewardsLoginModal, rewardsBalancesQuery, dailyRewardQuery, rewardsApiToken, isRewardsInitialized ]); }, [ pathname ]);
} }
...@@ -17,8 +17,6 @@ type NavItemCommon = { ...@@ -17,8 +17,6 @@ type NavItemCommon = {
export type NavItemInternal = NavItemCommon & { export type NavItemInternal = NavItemCommon & {
nextRoute: Route; nextRoute: Route;
isActive?: boolean; isActive?: boolean;
onClick?: () => void;
isDisabled?: boolean;
} }
export type NavItemExternal = { export type NavItemExternal = {
......
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'; ...@@ -3,6 +3,7 @@ import { animate, motion, useMotionValue } from 'framer-motion';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems'; import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems';
import RewardsNavLink from 'ui/rewards/RewardsNavLink';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import useIsAuth from 'ui/snippets/auth/useIsAuth'; import useIsAuth from 'ui/snippets/auth/useIsAuth';
...@@ -82,6 +83,7 @@ const NavigationMobile = ({ onNavLinkClick, isMarketplaceAppPage }: Props) => { ...@@ -82,6 +83,7 @@ const NavigationMobile = ({ onNavLinkClick, isMarketplaceAppPage }: Props) => {
borderColor="divider" borderColor="divider"
> >
<VStack as="ul" spacing="1" alignItems="flex-start"> <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 }/>) } { accountNavItems.map((item) => <NavLink key={ item.text } item={ item } onClick={ onNavLinkClick } isCollapsed={ isCollapsed }/>) }
</VStack> </VStack>
</Box> </Box>
......
...@@ -7,5 +7,5 @@ export function checkRouteHighlight(item: NavItem | Array<NavItem> | Array<Array ...@@ -7,5 +7,5 @@ export function checkRouteHighlight(item: NavItem | Array<NavItem> | Array<Array
if (Array.isArray(item)) { if (Array.isArray(item)) {
return item.some((subItem) => checkRouteHighlight(subItem)); 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 ...@@ -34,19 +34,13 @@ const NavLink = ({ item, isCollapsed, px, className, onClick, disableActiveState
const styleProps = useNavLinkStyleProps({ isCollapsed, isExpanded, isActive: isInternalLink && item.isActive && !disableActiveState }); const styleProps = useNavLinkStyleProps({ isCollapsed, isExpanded, isActive: isInternalLink && item.isActive && !disableActiveState });
const isXLScreen = useBreakpointValue({ base: false, xl: true }); const isXLScreen = useBreakpointValue({ base: false, xl: true });
let href; const href = isInternalLink ? route(item.nextRoute) : item.url;
if (isInternalLink && !item.onClick) {
href = route(item.nextRoute);
} else if ('url' in item) {
href = item.url;
}
const isHighlighted = checkRouteHighlight(item); const isHighlighted = checkRouteHighlight(item);
const isDisabled = isInternalLink && item.isDisabled;
const content = ( const content = (
<Link <Link
href={ isDisabled ? undefined : href } href={ href }
target={ isInternalLink ? '_self' : '_blank' } target={ isInternalLink ? '_self' : '_blank' }
{ ...styleProps.itemProps } { ...styleProps.itemProps }
w={{ base: '100%', lg: isExpanded ? '100%' : '60px', xl: isCollapsed ? '60px' : '100%' }} w={{ base: '100%', lg: isExpanded ? '100%' : '60px', xl: isCollapsed ? '60px' : '100%' }}
...@@ -55,11 +49,10 @@ const NavLink = ({ item, isCollapsed, px, className, onClick, disableActiveState ...@@ -55,11 +49,10 @@ const NavLink = ({ item, isCollapsed, px, className, onClick, disableActiveState
px={ px || { base: 2, lg: isExpanded ? 2 : '15px', xl: isCollapsed ? '15px' : 2 } } px={ px || { base: 2, lg: isExpanded ? 2 : '15px', xl: isCollapsed ? '15px' : 2 } }
aria-label={ `${ item.text } link` } aria-label={ `${ item.text } link` }
whiteSpace="nowrap" whiteSpace="nowrap"
as={ isInternalLink && item.onClick ? 'button' : 'a' } onClick={ onClick }
onClick={ isInternalLink && item.onClick ? item.onClick : onClick }
_hover={{ _hover={{
[`& *:not(.${ LIGHTNING_LABEL_CLASS_NAME }, .${ LIGHTNING_LABEL_CLASS_NAME } *)`]: { [`& *: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 ...@@ -89,7 +82,7 @@ const NavLink = ({ item, isCollapsed, px, className, onClick, disableActiveState
return ( return (
<Box as="li" listStyleType="none" w="100%" className={ className }> <Box as="li" listStyleType="none" w="100%" className={ className }>
{ isInternalLink && !item.onClick && !isDisabled ? ( { isInternalLink ? (
<NextLink href={ item.nextRoute } passHref legacyBehavior> <NextLink href={ item.nextRoute } passHref legacyBehavior>
{ content } { content }
</NextLink> </NextLink>
......
...@@ -6,6 +6,7 @@ import { useAppContext } from 'lib/contexts/app'; ...@@ -6,6 +6,7 @@ import { useAppContext } from 'lib/contexts/app';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems'; import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps'; import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
import RewardsNavLink from 'ui/rewards/RewardsNavLink';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import useIsAuth from 'ui/snippets/auth/useIsAuth'; import useIsAuth from 'ui/snippets/auth/useIsAuth';
import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo'; import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo';
...@@ -100,6 +101,7 @@ const NavigationDesktop = () => { ...@@ -100,6 +101,7 @@ const NavigationDesktop = () => {
{ isAuth && ( { isAuth && (
<Box as="nav" borderTopWidth="1px" borderColor="divider" w="100%" mt={ 3 } pt={ 3 }> <Box as="nav" borderTopWidth="1px" borderColor="divider" w="100%" mt={ 3 } pt={ 3 }>
<VStack as="ul" spacing="1" alignItems="flex-start"> <VStack as="ul" spacing="1" alignItems="flex-start">
<RewardsNavLink isCollapsed={ isCollapsed }/>
{ accountNavItems.map((item) => <NavLink key={ item.text } item={ item } isCollapsed={ isCollapsed }/>) } { accountNavItems.map((item) => <NavLink key={ item.text } item={ item } isCollapsed={ isCollapsed }/>) }
</VStack> </VStack>
</Box> </Box>
......
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