feat(PBI-59): JobsBoard 3-kolom SplitPane client component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e276cac922
commit
cd4ca4279f
1 changed files with 96 additions and 0 deletions
96
components/jobs/jobs-board.tsx
Normal file
96
components/jobs/jobs-board.tsx
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { SplitPane } from '@/components/split-pane/split-pane'
|
||||
import JobCard from './job-card'
|
||||
import JobDetailPane from './job-detail-pane'
|
||||
import SprintSubTasksPane from './sprint-sub-tasks-pane'
|
||||
import { useJobsStore } from '@/stores/jobs-store'
|
||||
import useJobsRealtime from '@/hooks/use-jobs-realtime'
|
||||
import type { JobWithRelations } from '@/actions/jobs-page'
|
||||
|
||||
interface JobsBoardProps {
|
||||
initialActiveJobs: JobWithRelations[]
|
||||
initialDoneJobs: JobWithRelations[]
|
||||
}
|
||||
|
||||
function jobToCardProps(j: JobWithRelations) {
|
||||
return {
|
||||
id: j.id,
|
||||
kind: j.kind,
|
||||
status: j.status,
|
||||
taskCode: j.taskCode,
|
||||
taskTitle: j.taskTitle,
|
||||
ideaCode: j.ideaCode,
|
||||
ideaTitle: j.ideaTitle,
|
||||
sprintGoal: j.sprintGoal,
|
||||
sprintCode: j.sprintCode,
|
||||
productName: j.productName,
|
||||
branch: j.branch,
|
||||
error: j.error,
|
||||
summary: j.summary,
|
||||
}
|
||||
}
|
||||
|
||||
export default function JobsBoard({ initialActiveJobs, initialDoneJobs }: JobsBoardProps) {
|
||||
const { activeJobs, doneJobs, selectedJobId, initJobs, setSelectedJobId } = useJobsStore()
|
||||
useJobsRealtime()
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => { initJobs(initialActiveJobs, initialDoneJobs) }, [])
|
||||
|
||||
const selectedJob = [...activeJobs, ...doneJobs].find(j => j.id === selectedJobId) ?? null
|
||||
|
||||
const leftPane = (
|
||||
<div className="overflow-y-auto h-full p-2 space-y-2">
|
||||
{activeJobs.map(j => (
|
||||
<JobCard
|
||||
key={j.id}
|
||||
{...jobToCardProps(j)}
|
||||
isSelected={j.id === selectedJobId}
|
||||
onClick={() => setSelectedJobId(j.id)}
|
||||
/>
|
||||
))}
|
||||
{activeJobs.length === 0 && (
|
||||
<p className="text-sm text-muted-foreground text-center py-8">Geen actieve jobs</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
const middlePane = (
|
||||
<div className="flex flex-col h-full overflow-hidden">
|
||||
<SprintSubTasksPane
|
||||
jobId={selectedJobId}
|
||||
isSprintJob={selectedJob?.kind === 'SPRINT_IMPLEMENTATION'}
|
||||
/>
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<JobDetailPane job={selectedJob} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const rightPane = (
|
||||
<div className="overflow-y-auto h-full p-2 space-y-2">
|
||||
{doneJobs.map(j => (
|
||||
<JobCard
|
||||
key={j.id}
|
||||
{...jobToCardProps(j)}
|
||||
isSelected={j.id === selectedJobId}
|
||||
onClick={() => setSelectedJobId(j.id)}
|
||||
/>
|
||||
))}
|
||||
{doneJobs.length === 0 && (
|
||||
<p className="text-sm text-muted-foreground text-center py-8">Nog geen afgeronde jobs</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<SplitPane
|
||||
panes={[leftPane, middlePane, rightPane]}
|
||||
defaultSplit={[25, 50, 25]}
|
||||
cookieKey="jobs"
|
||||
tabLabels={['Actief', 'Details', 'Klaar']}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue