11import type { Guest , JoinRequest , Member } from "@/types/collaboration" ;
2- import { UserPlus } from "lucide-react" ;
2+ import { UserPlus , ChevronLeft , ChevronRight , Users , UserCheck , UserPlus2 } from "lucide-react" ;
33import { useState } from "react" ;
44import MembersTab from "./member/MembersTab" ;
55import GuestsTab from "./member/GuestsTab" ;
@@ -9,13 +9,13 @@ import InviteModal from "./member/InviteModal";
99type TabType = 'members' | 'guests' | 'requests' ;
1010
1111const sampleMembers : Member [ ] = [
12- { id : '1' , name : 'Ha.NguyenVan' , username : '@hanguyenvan9' , lastActive : 'November 2025' , boardCount : 1 , isAdmin : true } ,
13- { id : '2' , name : 'Long.LeVanQuoc' , username : '@longlevanquoc1' , lastActive : 'October 2025' , boardCount : 1 , isAdmin : true } ,
14- { id : '3' , name : 'Lâm Nhất Nguyên' , username : '@nguyenlamnhat' , lastActive : 'November 2025' , boardCount : 2 , isAdmin : true } ,
15- { id : '4' , name : 'Nhien Tran Duc' , username : '@nhientranduc' , lastActive : 'November 2025' , boardCount : 1 , isAdmin : true } ,
16- { id : '5' , name : 'Hiển Lương' , username : '@tranhienluong2003' , lastActive : 'November 2025' , boardCount : 4 , isAdmin : true } ,
17- { id : '6' , name : 'Vu Tran' , username : '@vutran308' , lastActive : 'November 2025' , boardCount : 3 , isAdmin : true } ,
18- { id : '7' , name : 'NguyenHuuTuan' , username : '@tuungnhu12' , lastActive : 'September 2025' , boardCount : 1 , isAdmin : true } ,
12+ { userId : '1' , name : 'Ha.NguyenVan' , username : '@hanguyenvan9' , lastActive : 'November 2025' , boardCount : 1 , isAdmin : true } ,
13+ { userId : '2' , name : 'Long.LeVanQuoc' , username : '@longlevanquoc1' , lastActive : 'October 2025' , boardCount : 1 , isAdmin : true } ,
14+ { userId : '3' , name : 'Lâm Nhất Nguyên' , username : '@nguyenlamnhat' , lastActive : 'November 2025' , boardCount : 2 , isAdmin : true } ,
15+ { userId : '4' , name : 'Nhien Tran Duc' , username : '@nhientranduc' , lastActive : 'November 2025' , boardCount : 1 , isAdmin : true } ,
16+ { userId : '5' , name : 'Hiển Lương' , username : '@tranhienluong2003' , lastActive : 'November 2025' , boardCount : 4 , isAdmin : true } ,
17+ { userId : '6' , name : 'Vu Tran' , username : '@vutran308' , lastActive : 'November 2025' , boardCount : 3 , isAdmin : true } ,
18+ { userId : '7' , name : 'NguyenHuuTuan' , username : '@tuungnhu12' , lastActive : 'September 2025' , boardCount : 1 , isAdmin : true } ,
1919] ;
2020
2121const sampleGuests : Guest [ ] = [ ] ;
@@ -25,54 +25,133 @@ const sampleRequests: JoinRequest[] = [];
2525const WorkspaceCollaborators : React . FC = ( ) => {
2626 const [ activeTab , setActiveTab ] = useState < TabType > ( 'members' ) ;
2727 const [ isInviteModalOpen , setIsInviteModalOpen ] = useState ( false ) ;
28+ const [ isSidebarCollapsed , setIsSidebarCollapsed ] = useState ( false ) ;
2829 const [ members ] = useState < Member [ ] > ( sampleMembers ) ;
2930 const [ guests ] = useState < Guest [ ] > ( sampleGuests ) ;
3031 const [ requests ] = useState < JoinRequest [ ] > ( sampleRequests ) ;
3132
3233 const totalCollaborators = members . length + guests . length ;
3334
35+ const getTabIcon = ( tab : TabType ) => {
36+ switch ( tab ) {
37+ case 'members' : return < Users size = { 20 } /> ;
38+ case 'guests' : return < UserCheck size = { 20 } /> ;
39+ case 'requests' : return < UserPlus2 size = { 20 } /> ;
40+ }
41+ } ;
42+
43+ const getTabLabel = ( tab : TabType , count : number ) => {
44+ switch ( tab ) {
45+ case 'members' : return `Workspace members (${ count } )` ;
46+ case 'guests' : return `Guests (${ count } )` ;
47+ case 'requests' : return `Join requests (${ count } )` ;
48+ }
49+ } ;
50+
3451 return (
35- < div className = "h-full bg-[#1F1F21] text-white p-8" >
36- < div className = "w-full" >
37- < div className = "flex justify-between items-center mb-6" >
38- < h1 className = "text-xl font-bold" >
39- Collaborators < span className = "text-gray-400 " > { totalCollaborators } / 10</ span >
52+ < div className = "h-full bg-background text-foreground p-8 overflow-auto " >
53+ < div className = "w-full max-w-7xl mx-auto " >
54+ < div className = "flex justify-between items-center mb-6 animate-in fade-in slide-in-from-top-4 duration-500 " >
55+ < h1 className = "text-xl font-bold text-foreground " >
56+ Collaborators < span className = "text-muted-foreground " > { totalCollaborators } / 10</ span >
4057 </ h1 >
4158 < button
4259 onClick = { ( ) => setIsInviteModalOpen ( true ) }
43- className = "bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded flex items-center gap-2"
60+ className = "bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded flex items-center gap-2
61+ transition-all duration-200
62+ hover:scale-105 hover:shadow-lg hover:shadow-blue-500/50
63+ active:scale-95
64+ group"
4465 >
45- < UserPlus size = { 18 } />
66+ < UserPlus size = { 18 } className = "group-hover:scale-110 transition-transform duration-200" />
4667 Invite Workspace members
4768 </ button >
4869 </ div >
4970
5071 < div className = "flex gap-6" >
51- < div className = "w-64 space-y-2" >
72+ { /* Collapsible Sidebar */ }
73+ < div
74+ className = { `relative space-y-2 animate-in fade-in slide-in-from-left-4 duration-500 delay-100
75+ ${ isSidebarCollapsed ? 'w-16' : 'w-64' }
76+ transition-all duration-500 ease-in-out` }
77+ >
78+ { /* Collapse Toggle Button */ }
79+ < button
80+ onClick = { ( ) => setIsSidebarCollapsed ( ! isSidebarCollapsed ) }
81+ className = "absolute -right-3 top-0 z-10 bg-blue-600 hover:bg-blue-700 text-white rounded-full p-1.5
82+ transition-all duration-300 hover:scale-110 hover:rotate-180 shadow-lg active:scale-95"
83+ title = { isSidebarCollapsed ? "Expand sidebar" : "Collapse sidebar" }
84+ >
85+ { isSidebarCollapsed ? < ChevronRight size = { 16 } /> : < ChevronLeft size = { 16 } /> }
86+ </ button >
87+
88+ { /* Tab Buttons */ }
5289 < button
5390 onClick = { ( ) => setActiveTab ( 'members' ) }
54- className = { `cursor-pointer w-full text-left px-4 py-2 rounded ${ activeTab === 'members' ? 'bg-blue-600 text-white' : 'text-gray-400 hover:bg-neutral-800'
55- } `}
91+ className = { `relative w-full ${ isSidebarCollapsed ? 'px-2 justify-center' : 'px-4 justify-start' } text-left py-2 rounded overflow-hidden flex items-center gap-3
92+ transition-all duration-500 ease-in-out
93+ ${ activeTab === 'members'
94+ ? 'bg-blue-600 text-white shadow-lg shadow-blue-500/50'
95+ : 'text-muted-foreground hover:bg-muted hover:text-foreground hover:scale-105'
96+ }
97+ ` }
98+ title = { isSidebarCollapsed ? getTabLabel ( 'members' , members . length ) : undefined }
5699 >
57- Workspace members ({ members . length } )
100+ { activeTab === 'members' && (
101+ < div className = "absolute inset-0 bg-gradient-to-r from-blue-600 to-blue-500 animate-in fade-in duration-300" > </ div >
102+ ) }
103+ < span className = "relative z-10 transition-transform duration-300" > { getTabIcon ( 'members' ) } </ span >
104+ < span className = { `relative z-10 whitespace-nowrap transition-all duration-500 ease-in-out
105+ ${ isSidebarCollapsed ? 'opacity-0 w-0 overflow-hidden' : 'opacity-100' } ` } >
106+ Workspace members ({ members . length } )
107+ </ span >
58108 </ button >
109+
59110 < button
60111 onClick = { ( ) => setActiveTab ( 'guests' ) }
61- className = { `cursor-pointer w-full text-left px-4 py-2 rounded ${ activeTab === 'guests' ? 'bg-blue-600 text-white' : 'text-gray-400 hover:bg-neutral-800'
62- } `}
112+ className = { `relative w-full ${ isSidebarCollapsed ? 'px-2 justify-center' : 'px-4 justify-start' } text-left py-2 rounded overflow-hidden flex items-center gap-3
113+ transition-all duration-500 ease-in-out
114+ ${ activeTab === 'guests'
115+ ? 'bg-blue-600 text-white shadow-lg shadow-blue-500/50'
116+ : 'text-muted-foreground hover:bg-muted hover:text-foreground hover:scale-105'
117+ }
118+ ` }
119+ title = { isSidebarCollapsed ? getTabLabel ( 'guests' , guests . length ) : undefined }
63120 >
64- Guests ({ guests . length } )
121+ { activeTab === 'guests' && (
122+ < div className = "absolute inset-0 bg-gradient-to-r from-blue-600 to-blue-500 animate-in fade-in duration-300" > </ div >
123+ ) }
124+ < span className = "relative z-10 transition-transform duration-300" > { getTabIcon ( 'guests' ) } </ span >
125+ < span className = { `relative z-10 whitespace-nowrap transition-all duration-500 ease-in-out
126+ ${ isSidebarCollapsed ? 'opacity-0 w-0 overflow-hidden' : 'opacity-100' } ` } >
127+ Guests ({ guests . length } )
128+ </ span >
65129 </ button >
130+
66131 < button
67132 onClick = { ( ) => setActiveTab ( 'requests' ) }
68- className = { `cursor-pointer w-full text-left px-4 py-2 rounded ${ activeTab === 'requests' ? 'bg-blue-600 text-white' : 'text-gray-400 hover:bg-neutral-800'
69- } `}
133+ className = { `relative w-full ${ isSidebarCollapsed ? 'px-2 justify-center' : 'px-4 justify-start' } text-left py-2 rounded overflow-hidden flex items-center gap-3
134+ transition-all duration-500 ease-in-out
135+ ${ activeTab === 'requests'
136+ ? 'bg-blue-600 text-white shadow-lg shadow-blue-500/50'
137+ : 'text-muted-foreground hover:bg-muted hover:text-foreground hover:scale-105'
138+ }
139+ ` }
140+ title = { isSidebarCollapsed ? getTabLabel ( 'requests' , requests . length ) : undefined }
70141 >
71- Join requests ({ requests . length } )
142+ { activeTab === 'requests' && (
143+ < div className = "absolute inset-0 bg-gradient-to-r from-blue-600 to-blue-500 animate-in fade-in duration-300" > </ div >
144+ ) }
145+ < span className = "relative z-10 transition-transform duration-300" > { getTabIcon ( 'requests' ) } </ span >
146+ < span className = { `relative z-10 whitespace-nowrap transition-all duration-500 ease-in-out
147+ ${ isSidebarCollapsed ? 'opacity-0 w-0 overflow-hidden' : 'opacity-100' } ` } >
148+ Join requests ({ requests . length } )
149+ </ span >
72150 </ button >
73151 </ div >
74152
75- < div className = "flex-1" >
153+ { /* Main Content */ }
154+ < div className = "flex-1 min-w-0" >
76155 { activeTab === 'members' && < MembersTab members = { members } /> }
77156 { activeTab === 'guests' && < GuestsTab guests = { guests } /> }
78157 { activeTab === 'requests' && < JoinRequestsTab requests = { requests } /> }
0 commit comments