'use client' import { useMemo } from 'react' import { useShallow } from 'zustand/react/shallow' import { Button } from '@/components/ui/button' import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover' import JobCard from './job-card' import { JOB_STATUS_LABELS } from '@/components/shared/job-status' import { jobStatusToApi, type ClaudeJobStatusApi } from '@/lib/job-status' import { useUserSettingsStore } from '@/stores/user-settings/store' import { cn } from '@/lib/utils' import { debugProps } from '@/lib/debug' import type { JobWithRelations } from '@/actions/jobs-page' import type { ClaudeJobKind } from '@prisma/client' const KIND_LABELS: Record = { TASK_IMPLEMENTATION: 'TAAK', SPRINT_IMPLEMENTATION: 'SPRINT', IDEA_GRILL: 'GRILL', IDEA_MAKE_PLAN: 'PLAN', IDEA_REVIEW_PLAN: 'REVIEW', PLAN_CHAT: 'CHAT', } const KIND_OPTIONS: Array<{ value: ClaudeJobKind; label: string }> = [ { value: 'TASK_IMPLEMENTATION', label: 'TAAK' }, { value: 'SPRINT_IMPLEMENTATION', label: 'SPRINT' }, { value: 'IDEA_GRILL', label: 'GRILL' }, { value: 'IDEA_MAKE_PLAN', label: 'PLAN' }, { value: 'IDEA_REVIEW_PLAN', label: 'REVIEW' }, { value: 'PLAN_CHAT', label: 'CHAT' }, ] const KIND_VALUES = new Set(KIND_OPTIONS.map((o) => o.value)) function MultiFilterPills({ label, options, selected, onToggle, onClear, }: { label: string options: Array<{ value: T; label: string }> selected: Set onToggle: (v: T) => void onClear: () => void }) { const allActive = selected.size === 0 return (

{label}

{options.map((opt) => { const active = selected.has(opt.value) return ( ) })}
) } interface JobsColumnProps { title: string jobs: JobWithRelations[] selectedJobId: string | null onSelect: (id: string) => void storageKeyPrefix: string statusOptions: Array<{ value: ClaudeJobStatusApi; label: string }> emptyText: string } export default function JobsColumn({ title, jobs, selectedJobId, onSelect, storageKeyPrefix, statusOptions, emptyText, }: JobsColumnProps) { const allowedStatuses = useMemo( () => new Set(statusOptions.map((o) => o.value)), [statusOptions], ) const colPrefs = useUserSettingsStore( useShallow((s) => s.entities.settings.views?.jobsColumns?.[storageKeyPrefix]), ) const setPref = useUserSettingsStore((s) => s.setPref) const filterKinds = useMemo>(() => { const out = new Set() for (const v of colPrefs?.kinds ?? []) { if (KIND_VALUES.has(v as ClaudeJobKind)) out.add(v as ClaudeJobKind) } return out }, [colPrefs?.kinds]) const filterStatuses = useMemo>(() => { const out = new Set() for (const v of colPrefs?.statuses ?? []) { if (allowedStatuses.has(v as ClaudeJobStatusApi)) out.add(v as ClaudeJobStatusApi) } return out }, [colPrefs?.statuses, allowedStatuses]) function persist(kinds: Set, statuses: Set) { void setPref(['views', 'jobsColumns', storageKeyPrefix], { kinds: Array.from(kinds), statuses: Array.from(statuses), }) } function toggleKind(v: ClaudeJobKind) { const next = new Set(filterKinds) if (next.has(v)) next.delete(v) else next.add(v) persist(next, filterStatuses) } function toggleStatus(v: ClaudeJobStatusApi) { const next = new Set(filterStatuses) if (next.has(v)) next.delete(v) else next.add(v) persist(filterKinds, next) } const filtered = jobs.filter((j) => { if (filterKinds.size > 0 && !filterKinds.has(j.kind)) return false if (filterStatuses.size > 0 && !filterStatuses.has(jobStatusToApi(j.status))) return false return true }) const activeFilterCount = filterKinds.size + filterStatuses.size return (
{title}
{Array.from(filterKinds).map((k) => ( ))} {Array.from(filterStatuses).map((s) => ( ))} {`Filters${activeFilterCount > 0 ? ` (${activeFilterCount})` : ''}`} } /> persist(new Set(), filterStatuses)} /> persist(filterKinds, new Set())} />
{filtered.map((j) => ( onSelect(j.id)} /> ))} {filtered.length === 0 && (

{jobs.length === 0 ? emptyText : 'Geen jobs voldoen aan filter'}

)}
) }