Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions app/layouts/MobileBottomNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
faBars,
} from '@fortawesome/pro-light-svg-icons';
import { faXTwitter, faDiscord, faGithub, faLinkedin } from '@fortawesome/free-brands-svg-icons';
import { Sprout } from 'lucide-react';
import { Sprout, Star } from 'lucide-react';
import { ChangelogLink } from '@/components/changelog/ChangelogLink';
import { Icon } from '@/components/ui/icons';
import { IconName } from '@/components/ui/icons/Icon';
Expand All @@ -22,7 +22,7 @@ import { SwipeableDrawer } from '@/components/ui/SwipeableDrawer';
import { useAuthenticatedAction } from '@/contexts/AuthModalContext';
import { useCurrencyPreference } from '@/contexts/CurrencyPreferenceContext';
import { useScrollContainer } from '@/contexts/ScrollContainerContext';
import { useUser } from '@/contexts/UserContext';
import { isHomeTabPath } from '@/hooks/useFundTabs';

interface NavItem {
label: string;
Expand All @@ -43,11 +43,11 @@ const moreNavItems: NavItem[] = [

// Check if a path is active
const isPathActive = (path: string, currentPath: string): boolean => {
if (path === '/for-you' || path === '/popular') {
return ['/popular', '/for-you', '/latest', '/following', '/'].includes(currentPath);
if (path === '/') {
return isHomeTabPath(currentPath);
}
if (path === '/fund') {
return currentPath.startsWith('/fund');
if (path === '/fund/dashboard') {
return currentPath === '/fund/dashboard' || currentPath.startsWith('/fund/dashboard/');
}
if (path === '/notebook') {
return currentPath.startsWith('/notebook');
Expand All @@ -73,15 +73,11 @@ export const MobileBottomNav: React.FC = () => {
const { executeAuthenticatedAction } = useAuthenticatedAction();
const { showUSD, toggleCurrency } = useCurrencyPreference();
const scrollContainerRef = useScrollContainer();
const { user } = useUser();

// Home href depends on auth state: logged in -> /for-you, logged out -> /popular
const homeHref = user ? '/for-you' : '/popular';

const mainNavItems: NavItem[] = [
{ label: 'Home', href: homeHref, iconKey: 'home', isDynamicHome: true },
{ label: 'Earn', href: '/earn', iconKey: 'earn' },
{ label: 'Fund', href: '/fund', iconKey: 'fund' },
{ label: 'Home', href: '/', iconKey: 'home', isDynamicHome: true },
{ label: 'Peer Review', href: '/earn', iconKey: 'peer-review' },
{ label: 'Your Funding', href: '/fund/dashboard', iconKey: 'fund', requiresAuth: true },
{ label: 'Wallet', href: '/researchcoin', iconKey: 'wallet' },
{ label: 'More', isMore: true, iconKey: 'more' },
];
Expand Down Expand Up @@ -142,6 +138,15 @@ export const MobileBottomNav: React.FC = () => {
color={iconColor}
/>
);
case 'peer-review':
return (
<Star
size={iconSize}
color={iconColor}
strokeWidth={isActive ? 2.25 : 2}
fill={isActive ? iconColor : 'none'}
/>
);
case 'earn':
return (
<Icon
Expand Down
38 changes: 21 additions & 17 deletions app/layouts/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faHouse as faHouseSolid } from '@fortawesome/pro-solid-svg-icons';
import { faHouse as faHouseLight } from '@fortawesome/pro-light-svg-icons';
import { Sprout } from 'lucide-react';
import { Sprout, Star } from 'lucide-react';
import { Badge } from '@/components/ui/Badge';
import { useDismissableFeature } from '@/hooks/useDismissableFeature';
import { useUser } from '@/contexts/UserContext';
import { isHomeTabPath } from '@/hooks/useFundTabs';

const ENDOWMENT_NAV_FEATURE = 'endowment_nav_new_badge';
// Stop showing the "New" badge on the Endowment nav item after this date,
Expand All @@ -36,6 +36,7 @@
isUnimplemented?: boolean;
isFontAwesome?: boolean;
isLucideSprout?: boolean;
isLucideStar?: boolean;
/** Show a "New" badge next to the label. Pair with `newFeatureName` so the
* badge is dismissed once the user clicks the item. */
isNew?: boolean;
Expand Down Expand Up @@ -81,7 +82,6 @@
}) => {
const { executeAuthenticatedAction } = useAuthenticatedAction();
const router = useRouter();
const { user } = useUser();

// Dismissable "New" badge for the Endowment nav item. Lifted to the parent
// so the click handler in NavLink can call dismissFeature() without each
Expand All @@ -99,27 +99,25 @@
[router]
);

// Home href depends on auth state: logged in -> /for-you, logged out -> /popular
const homeHref = user ? '/for-you' : '/popular';

const navigationItems: NavigationItem[] = [
{
label: 'Home',
href: homeHref,
href: '/',
iconKey: 'home',
isFontAwesome: true,
description: 'Navigate to the home page',
},
{
label: 'Fund',
href: '/fund',
label: 'Your Funding',
href: '/fund/dashboard',
iconKey: 'fund',
Comment on lines +111 to 113

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate Your Funding behind auth

When a logged-out user clicks this new primary nav item, the Link goes straight to /fund/dashboard without using requiresAuth; that page then redirects unauthenticated users back to /, so the click appears to do nothing instead of opening sign-in and preserving the intended dashboard navigation. The analogous mobile nav item is also ungated, so please apply the same auth-gating behavior there.

Useful? React with 👍 / 👎.

description: 'Browse grants and fundraising opportunities',
requiresAuth: true,
description: 'Track the impact of the research you fund',
},
{
label: 'Earn',
label: 'Peer Review',
href: '/earn',
iconKey: 'earn',
isLucideStar: true,
description: 'Earn RSC for completing peer reviews',
},
{
Expand Down Expand Up @@ -152,13 +150,12 @@
};

const isPathActive = (path: string) => {
// Special case for home page
if (path === '/for-you' || path === '/popular') {
return ['/popular', '/for-you', '/latest', '/following'].includes(currentPath);
if (path === '/') {
return isHomeTabPath(currentPath);
}

if (path === '/fund') {
return currentPath.startsWith('/fund');
if (path === '/fund/dashboard') {
return currentPath === '/fund/dashboard' || currentPath.startsWith('/fund/dashboard/');
}

if (path === '/earn') {
Expand All @@ -185,7 +182,7 @@
showNewBadge?: boolean;
/** Fired alongside navigation to mark the new-badge feature as seen. */
onDismissNew?: () => void;
}> = ({ item, currentPath, onUnimplementedFeature, showNewBadge, onDismissNew }) => {

Check failure on line 185 in app/layouts/Navigation.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 27 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=ResearchHub_web&issues=AZ-9jVoWP1NBD9Gn6xEu&open=AZ-9jVoWP1NBD9Gn6xEu&pullRequest=984
const { executeAuthenticatedAction } = useAuthenticatedAction();
const router = useRouter();
const buttonStyles = getButtonStyles(item.href, currentPath);
Expand Down Expand Up @@ -243,11 +240,18 @@
/>
) : item.isLucideSprout ? (
<Sprout size={22} color={iconColor} strokeWidth={isActive ? 2.25 : 2} />
) : item.isLucideStar ? (
<Star
size={22}
color={iconColor}
strokeWidth={isActive ? 2.25 : 2}
fill={isActive ? iconColor : 'none'}
/>
) : item.iconKey ? (
<Icon name={getIconName() as IconName} size={26} color={iconColor} />
) : (
<div className="w-[26px] h-[26px]" />
)}

Check warning on line 254 in app/layouts/Navigation.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=ResearchHub_web&issues=AZ-9jVoWP1NBD9Gn6xEv&open=AZ-9jVoWP1NBD9Gn6xEv&pullRequest=984
</div>
<div className={textContainerClass}>
<span className="inline-flex items-center gap-2 truncate text-[16px] font-semibold">
Expand Down
48 changes: 12 additions & 36 deletions app/layouts/PublishMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { BaseMenu, BaseMenuItem } from '@/components/ui/form/BaseMenu';
import { FundingIcon } from '@/components/ui/icons/FundingIcon';
import { useAuthenticatedAction } from '@/contexts/AuthModalContext';
import Icon from '@/components/ui/icons/Icon';
import { useUser } from '@/contexts/UserContext';
import { navigateToAuthorProfile } from '@/utils/navigation';
import { SwipeableDrawer } from '@/components/ui/SwipeableDrawer';
import {
OpenFundingOpportunityModal,
Expand All @@ -27,33 +25,22 @@ interface PublishMenuProps {

const PUBLISH_MENU_SECTIONS = [
{
title: 'Publish on ResearchHub',
title: 'Post on ResearchHub',
items: [
{
id: 'give-funding',
title: 'Funding Opportunity',
description: 'Fund specific research you care about',
icon: <Icon name="fund" size={18} color="#374151" />,
action: 'function',
handler: 'handleOpenGrant',
handler: 'handleOpenGrant' as const,
requiresAuth: true,
},
{
id: 'request-funding',
title: 'Proposal',
description: 'Raise money for your research',
icon: <FundingIcon size={18} color="#374151" />,
action: 'function',
handler: 'handleFundResearch',
requiresAuth: true,
},
{
id: 'submit-paper',
title: 'Preprint',
description: 'Publish your research as a preprint',
icon: <Icon name="submit1" size={18} color="#374151" />,
action: 'navigate',
path: '/notebook?newResearch=true',
handler: 'handleFundResearch' as const,
requiresAuth: true,
},
],
Expand Down Expand Up @@ -86,7 +73,6 @@ const MenuItemContent: React.FC<MenuItemContentProps> = ({ icon, title, descript
export const PublishMenu: React.FC<PublishMenuProps> = ({ children, forceMinimize = false }) => {
const router = useRouter();
const { executeAuthenticatedAction } = useAuthenticatedAction();
const { user } = useUser();
const { smAndDown } = useScreenSize();
const [isMobileDrawerOpen, setIsMobileDrawerOpen] = useState(false);
const [isFundingOpportunityModalOpen, setIsFundingOpportunityModalOpen] = useState(false);
Expand All @@ -110,28 +96,18 @@ export const PublishMenu: React.FC<PublishMenuProps> = ({ children, forceMinimiz
router.push(`/notebook?newGrant=true&grantSource=${method}`);
};

const handleViewProfile = () => {
navigateToAuthorProfile(user?.id, false);
};

const handleMenuItemClick = (item: (typeof PUBLISH_MENU_SECTIONS)[number]['items'][number]) => {
if (item.requiresAuth) {
executeAuthenticatedAction(() => {
if (item.action === 'navigate') {
router.push(item.path);
} else if (item.action === 'function') {
switch (item.handler) {
case 'handleFundResearch':
handleFundResearch();
break;
case 'handleOpenGrant':
handleOpenGrant();
break;
}
switch (item.handler) {
case 'handleFundResearch':
handleFundResearch();
break;
case 'handleOpenGrant':
handleOpenGrant();
break;
}
});
} else if (item.action === 'navigate') {
router.push(item.path);
}

// Close mobile drawer after action
Expand All @@ -154,7 +130,7 @@ export const PublishMenu: React.FC<PublishMenuProps> = ({ children, forceMinimiz
}}
>
<Plus className="h-[22px] w-[22px] stroke-[1.5]" />
<span>Publish</span>
<span>Post</span>
</button>
);

Expand Down Expand Up @@ -248,7 +224,7 @@ export const PublishMenu: React.FC<PublishMenuProps> = ({ children, forceMinimiz
}}
role="button"
tabIndex={0}
aria-label="Open publish menu"
aria-label="Open post menu"
>
{standardTrigger}
{compactTrigger}
Expand Down