diff --git a/app/me/layout.tsx b/app/me/layout.tsx index 0560658f..85dabcb1 100644 --- a/app/me/layout.tsx +++ b/app/me/layout.tsx @@ -23,9 +23,14 @@ interface MeLayoutProfile { image?: string; joinedHackathons?: ProfileItemWithId[]; hackathonSubmissionsAsParticipant?: ProfileItemWithId[]; + projects?: ProfileItemWithId[]; }; image?: string; hackathonSubmissionsAsParticipant?: ProfileItemWithId[]; + projects?: ProfileItemWithId[]; + stats?: { + projectsCreated?: number; + }; } const getId = (item: ProfileItemWithId): string | undefined => @@ -69,6 +74,25 @@ const MeLayout = ({ children }: MeLayoutProps): React.ReactElement => { }).length; }, [typedProfile]); + const projectsCount = useMemo(() => { + if (!typedProfile) return 0; + // stats.projectsCreated is often the most direct count + if (typeof typedProfile.stats?.projectsCreated === 'number') { + return typedProfile.stats.projectsCreated; + } + // Fallback to array lengths + const fromUser = typedProfile.user?.projects ?? []; + const fromProfile = typedProfile.projects ?? []; + const merged = [...fromUser, ...fromProfile]; + const seen = new Set(); + return merged.filter(p => { + const id = getId(p); + if (!id || seen.has(id)) return false; + seen.add(id); + return true; + }).length; + }, [typedProfile]); + // Only show full-screen spinner on first load, not on background refetches if (isLoading && !hasLoadedOnce.current) { return ( @@ -92,6 +116,7 @@ const MeLayout = ({ children }: MeLayoutProps): React.ReactElement => { counts={{ participating: hackathonsCount, submissions: submissionsCount, + projects: projectsCount, }} variant='inset' /> diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index ec78d978..c4703ddb 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -29,11 +29,13 @@ import { import Image from 'next/image'; import Link from 'next/link'; import { useNotificationStore } from '@/lib/stores/notification-store'; +import { Logo } from './landing-page/navbar'; const getNavigationData = (counts?: { participating?: number; unreadNotifications?: number; submissions?: number; + projects?: number; }) => ({ main: [ { @@ -57,7 +59,7 @@ const getNavigationData = (counts?: { title: 'My Projects', url: '/me/projects', icon: IconFolder, - badge: '3', + badge: (counts?.projects ?? 0) > 0 ? String(counts?.projects) : undefined, }, { title: 'Create Project', @@ -132,7 +134,7 @@ export function AppSidebar({ ...props }: { user: UserData; - counts?: { participating?: number; submissions?: number }; + counts?: { participating?: number; submissions?: number; projects?: number }; } & React.ComponentProps) { const unreadNotifications = useNotificationStore(state => state.unreadCount); @@ -164,17 +166,7 @@ export function AppSidebar({ size='lg' className='group hover:bg-sidebar-accent/0 transition-all duration-200' > - -
- Boundless Logo -
- + diff --git a/components/landing-page/navbar.tsx b/components/landing-page/navbar.tsx index 930ff85f..10cddc32 100644 --- a/components/landing-page/navbar.tsx +++ b/components/landing-page/navbar.tsx @@ -124,7 +124,7 @@ export function Navbar() { ); } -function Logo() { +export function Logo() { return (