Skip to content

Commit 3847ce4

Browse files
committed
fix: add backlog to kanban
1 parent 286ad5d commit 3847ce4

1 file changed

Lines changed: 106 additions & 7 deletions

File tree

src/components/Projects/SprintBoardView.tsx

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)