@@ -10,6 +10,7 @@ import { useUserStore } from "@/store/codev-store";
1010import { KanbanBoardType , KanbanColumnType } from "@/types/home/codev" ;
1111import { useQuery } from "@tanstack/react-query" ;
1212import toast from "react-hot-toast" ;
13+ import { Archive } from "lucide-react" ;
1314
1415import { Button } from "@codevs/ui/button" ;
1516
@@ -27,47 +28,29 @@ interface KanbanBoardProps {
2728 projectId : string ;
2829}
2930
30- /**
31- * Enhanced KanbanBoard component with three-level breadcrumb navigation
32- * and draft task card counter badge
33- *
34- * Features:
35- * - Three-level breadcrumb navigation
36- * - Draft task counter badge (CBP-16)
37- * - Archive toggle
38- * - Task filtering by user
39- * - Responsive design
40- *
41- * Follows KISS, YAGNI, DRY, and SOLID principles
42- */
4331function KanbanBoard ( { boardData, projectId } : KanbanBoardProps ) {
4432 const user = useUserStore ( ( state ) => state . user ) ;
4533
46- // Sync the Kanban task modal with the URL ?taskId param
4734 useKanbanTaskUrlModal ( boardData ) ;
4835
49- // User permissions - simple boolean checks following YAGNI principle
5036 const canAddColumn = user ?. role_id === 1 || user ?. role_id === 5 ;
5137 const canAddMember = canAddColumn ;
5238
53- // Component state - minimal and focused
5439 const [ activeFilter , setActiveFilter ] = useState < string | null > ( null ) ;
5540 const [ showArchive , setShowArchive ] = useState ( false ) ;
5641 const [ draftCount , setDraftCount ] = useState < number > ( 0 ) ;
5742
58- // Fetch project members using React Query for caching and optimization
5943 const { data : allMembers = [ ] , isLoading : isMembersLoading } = useQuery ( {
6044 queryKey : [ "members" , projectId ] ,
6145 queryFn : async ( ) => {
6246 const result = await getMembers ( projectId ) ;
6347 return result . data || [ ] ;
6448 } ,
6549 enabled : ! ! projectId ,
66- staleTime : 5 * 60 * 1000 , // 5 minutes cache
50+ staleTime : 5 * 60 * 1000 ,
6751 refetchOnWindowFocus : false ,
6852 } ) ;
6953
70- // Transform members data using useMemo for performance optimization
7154 const members = useMemo (
7255 ( ) =>
7356 allMembers . map ( ( user ) => ( {
@@ -79,32 +62,24 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
7962 [ allMembers , activeFilter ] ,
8063 ) ;
8164
82- // Load draft count when component mounts or user/project changes
8365 useEffect ( ( ) => {
8466 if ( user ?. id && projectId ) {
8567 loadDraftCount ( ) ;
8668 }
8769 } , [ user ?. id , projectId ] ) ;
8870
89- /**
90- * Fetch the number of draft task cards for the current user
91- * Updates the draftCount state for badge display
92- */
9371 const loadDraftCount = async ( ) => {
9472 if ( ! user ?. id || ! projectId ) return ;
95-
9673 const result = await getDraftCount ( projectId , user . id ) ;
9774 if ( result . success && result . count !== undefined ) {
9875 setDraftCount ( result . count ) ;
9976 }
10077 } ;
10178
102- // Filter handler using useCallback to prevent unnecessary re-renders
10379 const handleFilterClick = useCallback ( ( userId : string ) => {
10480 setActiveFilter ( ( prev ) => ( prev === userId ? null : userId ) ) ;
10581 } , [ ] ) ;
10682
107- // Early return for missing data - fail fast principle
10883 if ( ! boardData ) {
10984 return (
11085 < div className = "text-center text-red-500" > Board data not found.</ div >
@@ -120,12 +95,11 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
12095 className = "flex flex-row items-center gap-3 text-sm"
12196 aria-label = "Breadcrumb"
12297 >
123- { /* Level 1: Kanban Board Overview */ }
12498 < Link
12599 href = { pathsConfig . app . kanban }
126100 className = "group transition-colors duration-200"
127101 >
128- < span className = "group-hover: text-customBlue-600 dark: group-hover:text-customBlue-400 text-gray-500 dark:text-gray -400" >
102+ < span className = "text-gray-500 group-hover:text-customBlue-600 dark: text-gray-400 dark:group-hover: text-customBlue -400" >
129103 📋 Kanban Board
130104 </ span >
131105 </ Link >
@@ -135,12 +109,11 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
135109 aria-hidden = "true"
136110 />
137111
138- { /* Level 2: Project Sprint */ }
139112 < Link
140113 href = { `${ pathsConfig . app . kanban } /${ projectId } ` }
141114 className = "group transition-colors duration-200"
142115 >
143- < span className = "group-hover: text-customBlue-600 dark: group-hover:text-customBlue-400 text-gray-500 dark:text-gray -400" >
116+ < span className = "text-gray-500 group-hover:text-customBlue-600 dark: text-gray-400 dark:group-hover: text-customBlue -400" >
144117 Kanban Sprint
145118 </ span >
146119 </ Link >
@@ -150,9 +123,8 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
150123 aria-hidden = "true"
151124 />
152125
153- { /* Level 3: Current Board Name */ }
154126 < span
155- className = "to-customBlue-600 bg-gradient-to-r from-purple-600 bg-clip-text font-semibold text-gray-900 text- transparent dark:text-white "
127+ className = "bg-gradient-to-r from-purple-600 to-customBlue-600 bg-clip-text font-semibold text-transparent"
156128 aria-current = "page"
157129 >
158130 { boardData . name }
@@ -168,7 +140,7 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
168140 </ span >
169141 </ div >
170142 < div >
171- < h1 className = "to-customBlue-600 bg-gradient-to-r from-purple-600 bg-clip-text text-2xl font-bold text-transparent drop-shadow-sm md:text-3xl" >
143+ < h1 className = "bg-gradient-to-r from-purple-600 to-customBlue -600 bg-clip-text text-2xl font-bold text-transparent drop-shadow-sm md:text-3xl" >
172144 { boardData . name }
173145 </ h1 >
174146 < p className = "text-sm font-medium text-gray-600 dark:text-gray-400" >
@@ -178,19 +150,23 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
178150 </ div >
179151
180152 { /* Desktop Layout: Search Left, Controls Right */ }
181- < div className = "flex flex-col gap-6 lg:flex-row lg:gap-8 lg:items-start " >
153+ < div className = "flex flex-col gap-6 lg:flex-row lg:items-start lg:gap-8 " >
182154 { /* Left: Search Input */ }
183155 < div className = "flex-1" >
184- < div className = "focus-within:ring-customBlue-500 focus-within:border-customBlue-300 flex w-full items-center gap-3 rounded-xl border border-white/20 bg-white/10 p-3 shadow-lg backdrop-blur-sm transition-all duration-300 focus-within:shadow-xl focus-within:ring-2 hover:bg-white/20 dark:border-white/10 dark:bg-white/5" >
156+ < div className = "focus-within:ring-customBlue-500 focus-within:border-customBlue-300 flex w-full items-center gap-3 rounded-xl border p-3 shadow-lg backdrop-blur-sm transition-all duration-300 focus-within:shadow-xl focus-within:ring-2
157+ border-gray-200 bg-white hover:bg-gray-50
158+ dark:border-white/10 dark:bg-white/5 dark:hover:bg-white/10" >
185159 < label htmlFor = "kanbanSearch" className = "sr-only" >
186160 Search tasks
187161 </ label >
188162 < IconSearch
189- className = "text-gray-300 transition-colors duration-200 dark:text-gray-400"
163+ className = "text-gray-400 transition-colors duration-200 dark:text-gray-400"
190164 aria-hidden = "true"
191165 />
192166 < KanbanBoardsSearch
193- className = "w-full bg-transparent font-medium text-white placeholder-gray-300 outline-none dark:text-white dark:placeholder-gray-400"
167+ className = "w-full bg-transparent font-medium outline-none
168+ text-gray-800 placeholder-gray-400
169+ dark:text-white dark:placeholder-gray-400"
194170 placeholder = "🔍 Search tasks..."
195171 id = "kanbanSearch"
196172 />
@@ -206,18 +182,18 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
206182 ) }
207183 { canAddMember && < KanbanAddMembersButton /> }
208184
209- { /* Archive Toggle Button */ }
185+ { /* Archive Toggle Button - FIXED for light mode */ }
210186 < Button
211187 onClick = { ( ) => setShowArchive ( ! showArchive ) }
212188 variant = { showArchive ? "default" : "outline" }
213189 className = { `flex transform items-center gap-2 whitespace-nowrap px-3 py-2 text-sm transition-all duration-300 hover:scale-105 ${
214190 showArchive
215191 ? "bg-customBlue-600 hover:bg-customBlue-700 shadow-customBlue-500/30 text-white shadow-lg"
216- : "border-white/30 text-white hover:border-white/50 hover:bg-white/20 dark:border-white/20 dark:text-gray-300 dark:hover:bg-white/10 backdrop-blur-sm"
192+ : "border-gray-300 bg- white text-gray-700 hover:border-gray-400 hover:bg-gray-100 dark:border-white/20 dark:bg-transparent dark:text-gray-300 dark:hover:bg-white/10 backdrop-blur-sm"
217193 } `}
218194 aria-pressed = { showArchive }
219195 >
220- < IconArchive className = "h-4 w-4" aria-hidden = "true" />
196+ < Archive className = "h-4 w-4 text-gray-600 dark:text-gray-300 " aria-hidden = "true" />
221197 < span className = "hidden lg:inline" >
222198 { showArchive ? "Hide Archive" : "Show Archive" }
223199 </ span >
@@ -226,7 +202,7 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
226202 </ span >
227203 </ Button >
228204
229- { /* Draft Badge Button - CBP-16 */ }
205+ { /* Draft Badge Button - FIXED for light mode */ }
230206 { draftCount > 0 && (
231207 < Button
232208 onClick = { ( ) => {
@@ -236,13 +212,15 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
236212 } ) ;
237213 } }
238214 variant = "outline"
239- className = "relative flex transform items-center gap-2 whitespace-nowrap px-3 py-2 text-sm transition-all duration-300 hover:scale-105 border-white/30 text-white hover:border-white/50 hover:bg-white/20 dark:border-white/20 dark:text-gray-300 dark:hover:bg-white/10 backdrop-blur-sm"
215+ className = "relative flex transform items-center gap-2 whitespace-nowrap px-3 py-2 text-sm transition-all duration-300 hover:scale-105
216+ border-gray-300 bg-white text-gray-700 hover:border-gray-400 hover:bg-gray-100
217+ dark:border-white/20 dark:bg-transparent dark:text-gray-300 dark:hover:bg-white/10 backdrop-blur-sm"
240218 aria-label = { `You have ${ draftCount } draft${ draftCount > 1 ? 's' : '' } ` }
241219 title = "View your saved drafts"
242220 >
243221 < span className = "text-lg" aria-hidden = "true" > 📝</ span >
244222 < span className = "hidden lg:inline" > Drafts</ span >
245- < span className = "absolute -right-1 -top-1 flex h-5 w-5 items-center justify-center rounded-full bg-blue-500 text-xs text-white font-semibold shadow-lg" >
223+ < span className = "absolute -right-1 -top-1 flex h-5 w-5 items-center justify-center rounded-full bg-blue-500 text-xs font-semibold text-white shadow-lg" >
246224 { draftCount }
247225 </ span >
248226 </ Button >
@@ -263,7 +241,6 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
263241 { /* Main Content Area */ }
264242 < main className = "flex-1" >
265243 { boardData . kanban_columns . length === 0 ? (
266- // Empty State
267244 < div className = "flex flex-1 items-center justify-center" >
268245 < div className = "py-20 text-center" >
269246 < div
@@ -287,7 +264,6 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
287264 </ div >
288265 </ div >
289266 ) : (
290- // Kanban Board Content
291267 < div className = "flex h-full flex-1 overflow-hidden rounded-xl bg-transparent backdrop-blur-sm transition-all duration-300" >
292268 { ! showArchive ? (
293269 < KanbanBoardColumnContainer
@@ -304,7 +280,6 @@ function KanbanBoard({ boardData, projectId }: KanbanBoardProps) {
304280 </ div >
305281 </ div >
306282
307- { /* Modal Container */ }
308283 { canAddColumn && < KanbanColumnAddModal /> }
309284 </ div >
310285 ) ;
0 commit comments