@@ -277,6 +277,8 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
277277 selectedSprintIds . includes ( sprint . id . toString ( ) ) ,
278278 )
279279
280+ const backlogTasks = tasks . filter ( ( task ) => ! extractId ( task . sprint ) )
281+
280282 // Calculate the height to pass to columns
281283 const calculatedHeight =
282284 heroHeight > 0 ? `calc(100vh - ${ heroHeight + 120 } px)` : 'calc(100vh - 12rem)'
@@ -476,8 +478,105 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
476478 </ div >
477479
478480 { /* Sprint Columns Grid */ }
479- { visibleSprints . length > 0 ? (
480- < div className = "grid gap-6 h-full overflow-x-auto" style = { { gridTemplateColumns : `repeat(${ visibleSprints . length } , minmax(350px, 1fr))` } } >
481+ { visibleSprints . length > 0 || backlogTasks . length > 0 ? (
482+ < div className = "grid gap-6 h-full overflow-x-auto" style = { { gridTemplateColumns : `repeat(${ visibleSprints . length + 1 } , minmax(350px, 1fr))` } } >
483+ { /* Backlog Column */ }
484+ < Card
485+ className = "p-4 bg-card border-l-4 border-l-amber-500 shadow-sm hover:shadow-md transition-shadow duration-200 flex flex-col"
486+ style = { { height : calculatedHeight } }
487+ >
488+ { /* Column Header */ }
489+ < div className = "flex items-center justify-between mb-4 flex-shrink-0" >
490+ < div className = "flex items-center gap-2 flex-1 min-w-0" >
491+ < div className = "flex-1 min-w-0" >
492+ < h3 className = "font-semibold text-foreground text-lg truncate" >
493+ Backlog
494+ </ h3 >
495+ < p className = "text-xs text-muted-foreground" >
496+ Unscheduled tasks
497+ </ p >
498+ </ div >
499+ </ div >
500+ < Badge variant = "secondary" className = "bg-muted text-muted-foreground flex-shrink-0" >
501+ { backlogTasks . length }
502+ </ Badge >
503+ </ div >
504+
505+ { /* Tasks Container */ }
506+ < div className = "flex-1 overflow-y-auto space-y-4 min-h-0" >
507+ { /* Unassigned Tasks (No Epic) */ }
508+ { backlogTasks . filter ( ( t ) => ! extractId ( t . epic ) ) . length > 0 && (
509+ < div className = "space-y-3" >
510+ { backlogTasks
511+ . filter ( ( t ) => ! extractId ( t . epic ) )
512+ . map ( ( task ) => (
513+ < TaskCard
514+ key = { task . id }
515+ task = { task }
516+ epic = { null }
517+ onDragStart = { handleDragStart }
518+ onTaskClick = { handleTaskClick }
519+ isCompact = { false }
520+ />
521+ ) ) }
522+ </ div >
523+ ) }
524+
525+ { /* Tasks Grouped by Epic */ }
526+ { selectedEpicIds . map ( ( epicId ) => {
527+ const epic = epics . find ( ( e ) => e . id === epicId )
528+ const epicTasks = backlogTasks . filter ( ( t ) => extractId ( t . epic ) === epicId ) || [ ]
529+
530+ if ( epicTasks . length === 0 ) return null
531+
532+ return (
533+ < div key = { epicId } className = "mb-6" >
534+ < div className = "flex items-center gap-2 mb-3" >
535+ < div className = { `w-3 h-3 rounded-full ${ epic ?. color } ` } > </ div >
536+ < span className = "text-sm font-medium text-muted-foreground select-none" >
537+ { epic ?. name }
538+ </ span >
539+ < Badge variant = "secondary" className = "text-xs" >
540+ { epicTasks . length }
541+ </ Badge >
542+ </ div >
543+ < div className = "space-y-3" >
544+ { epicTasks . map ( ( task ) => (
545+ < TaskCard
546+ key = { task . id }
547+ task = { task }
548+ epic = { epic ! }
549+ onDragStart = { handleDragStart }
550+ onTaskClick = { handleTaskClick }
551+ isCompact = { false }
552+ />
553+ ) ) }
554+ </ div >
555+ </ div >
556+ )
557+ } ) }
558+
559+ { /* Empty State */ }
560+ { backlogTasks . length === 0 && (
561+ < div className = "flex items-center justify-center h-32 text-center" >
562+ < div >
563+ < p className = "text-sm text-muted-foreground" > No backlog tasks</ p >
564+ < Button
565+ variant = "outline"
566+ size = "sm"
567+ onClick = { ( ) => setIsAddTaskModalOpen ( true ) }
568+ className = "mt-2 gap-1"
569+ >
570+ < Plus className = "h-3 w-3" />
571+ Add task
572+ </ Button >
573+ </ div >
574+ </ div >
575+ ) }
576+ </ div >
577+ </ Card >
578+
579+ { /* Sprint Columns */ }
481580 { visibleSprints . map ( ( sprint ) => {
482581 const sprintTasks = tasks . filter ( ( task ) => extractId ( task . sprint ) === sprint . id )
483582 const tasksByEpic = getTasksByEpic ( sprintTasks )
@@ -586,16 +685,16 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
586685 < div className = "flex items-center justify-center h-full" >
587686 < div className = "text-center" >
588687 < Calendar className = "h-12 w-12 text-muted-foreground mx-auto mb-4 opacity-50" />
589- < p className = "text-lg font-medium text-foreground mb-2" > No sprints selected </ p >
688+ < p className = "text-lg font-medium text-foreground mb-2" > No tasks in backlog </ p >
590689 < p className = "text-sm text-muted-foreground mb-4" >
591- Select up to 3 sprints to get started
690+ Create your first task to get started
592691 </ p >
593692 < Button
594- onClick = { ( ) => setIsSprintSelectorOpen ( true ) }
693+ onClick = { ( ) => setIsAddTaskModalOpen ( true ) }
595694 className = "gap-1"
596695 >
597- < Calendar className = "h-4 w-4 " />
598- Select Sprints
696+ < Plus className = "h-3 w-3 " />
697+ Add Task
599698 </ Button >
600699 </ div >
601700 </ div >
0 commit comments