Skip to content
Merged
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
98 changes: 80 additions & 18 deletions components/app-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import { TeamsApi } from '@/api/teams/teams.api'
import { GetTeamsDto } from '@/api/teams/teams.type'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
import { Separator } from '@/components/ui/separator'
import {
Sidebar,
SidebarContent,
Expand All @@ -18,9 +20,10 @@ import { appConfig } from '@/config/app-config'
import { SIDEBAR_LINKS, TSidebarLink } from '@/config/sidebar'
import { cn } from '@/lib/utils'
import { useQuery } from '@tanstack/react-query'
import { PlusIcon, UserPlusIcon } from 'lucide-react'
import { ChevronDown, ChevronRight, PlusIcon, UserPlusIcon } from 'lucide-react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { useState } from 'react'
import StrideAppLogo from './Animated-logo'
import { Shimmer } from './Shimmer'

Expand All @@ -38,22 +41,6 @@ const getSidebarLinks = (teams?: GetTeamsDto): TSidebarLink[] => {
baseUrl: `/teams/${team.id}`,
}))

teamsLinks.push({
id: 'create_team_cta',
title: 'Create a team',
url: '/teams/create',
baseUrl: '/teams/create',
icon: PlusIcon,
})

teamsLinks.push({
id: 'join_team_cta',
title: 'Join a team',
url: '/teams/join',
baseUrl: '/teams/join',
icon: UserPlusIcon,
})

return [
...sidebarLinks,
{
Expand All @@ -63,6 +50,26 @@ const getSidebarLinks = (teams?: GetTeamsDto): TSidebarLink[] => {
baseUrl: '#',
items: teamsLinks,
},
{
id: 'separator',
title: '',
url: '#',
baseUrl: '#',
},
{
id: 'create_team_cta',
title: 'Create a team',
url: '/teams/create',
baseUrl: '/teams/create',
icon: PlusIcon,
},
{
id: 'join_team_cta',
title: 'Join a team',
url: '/teams/join',
baseUrl: '/teams/join',
icon: UserPlusIcon,
},
]
}

Expand All @@ -86,6 +93,55 @@ type SidebarLinkProps = {

const SidebarLink = ({ link }: SidebarLinkProps) => {
const pathname = usePathname()
const [isTeamsOpen, setIsTeamsOpen] = useState(true)

if (link.id === 'separator') {
return (
<div className="px-2 py-1">
<Separator />
</div>
)
}

if (link.items && link.id === 'teams_list') {
return (
<SidebarMenuItem className="px-2">
<Collapsible open={isTeamsOpen} onOpenChange={setIsTeamsOpen}>
Comment on lines +106 to +109
Copy link

Choose a reason for hiding this comment

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

Non-persistent Teams List Expansion State category Functionality

Tell me more
What is the issue?

The teams list collapsible state is not persisted, causing it to reset to closed state on page refresh or navigation.

Why this matters

Users will lose their preferred sidebar navigation state every time they refresh the page or navigate, leading to a poor user experience, especially for users who frequently access team-related features.

Suggested change ∙ Feature Preview

Store the collapsible state in localStorage to persist it across page refreshes. Modify the code as follows:

const [isTeamsOpen, setIsTeamsOpen] = useState(() => {
  if (typeof window !== 'undefined') {
    const stored = localStorage.getItem('teamsListOpen');
    return stored ? stored === 'true' : false;
  }
  return false;
});

const handleTeamsOpenChange = (open: boolean) => {
  setIsTeamsOpen(open);
  localStorage.setItem('teamsListOpen', String(open));
};

// In JSX:
<Collapsible open={isTeamsOpen} onOpenChange={handleTeamsOpenChange}>
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

<CollapsibleTrigger asChild>
<SidebarMenuButton className="w-full justify-between">
<div className="flex items-center gap-2">
<span>{link.title}</span>
</div>
{isTeamsOpen ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)}
</SidebarMenuButton>
</CollapsibleTrigger>

<CollapsibleContent className="pl-1">
<SidebarMenu>
{link.items.map((item) => (
<SidebarMenuItem key={item.id} className="px-2">
<SidebarMenuButton asChild isActive={pathname.startsWith(item.baseUrl)}>
<Link href={item.url}>
{item.icon && (
<div className="pr-0.5">
<item.icon className="h-4 w-4" />
</div>
)}
{item.title}
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</CollapsibleContent>
</Collapsible>
</SidebarMenuItem>
)
}

if (link.items) {
return (
Expand Down Expand Up @@ -123,7 +179,13 @@ const SidebarLink = ({ link }: SidebarLinkProps) => {
return (
<SidebarMenuItem className="px-2">
<SidebarMenuButton asChild isActive={pathname.startsWith(link.baseUrl)}>
<Link href={link.url}>
<Link
href={link.url}
className={cn(
(link.id === 'create_team_cta' || link.id === 'join_team_cta') &&
'opacity-75 hover:opacity-100 focus:opacity-100 active:opacity-100',
)}
>
{link.icon && (
<div className="pr-0.5">
<link.icon className="h-4 w-4" />
Expand Down
2 changes: 1 addition & 1 deletion modules/teams/components/teams-layout-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const TeamsLayoutHeader = ({ teamId }: TeamsLayoutHeaderProps) => {
<div className="flex items-center justify-between pt-6 pb-8">
<h2 className="text-2xl font-bold">{team?.name}</h2>

<Button size="sm" onClick={() => setIsAddMembersModalOpen(true)}>
<Button size="sm" onClick={() => setIsAddMembersModalOpen(true)} className="cursor-pointer">
<UserRoundPlusIcon />
Add members
</Button>
Expand Down