diff --git a/components/ideas/idea-list.tsx b/components/ideas/idea-list.tsx
index 2edac75..2b92ca2 100644
--- a/components/ideas/idea-list.tsx
+++ b/components/ideas/idea-list.tsx
@@ -10,9 +10,10 @@
import { useMemo, useState, useTransition } from 'react'
import { useRouter } from 'next/navigation'
-import { Plus } from 'lucide-react'
+import { Plus, ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react'
import { toast } from 'sonner'
+import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
@@ -50,6 +51,8 @@ interface ProductOption {
repo_url: string | null
}
+type SortKey = 'code' | 'title' | 'product' | 'status'
+
interface IdeaListProps {
ideas: IdeaDto[]
products: ProductOption[]
@@ -67,6 +70,38 @@ const STATUS_FILTERS: { value: IdeaStatusApi; label: string }[] = [
{ value: 'plan_failed', label: 'Plan mislukt' },
]
+function SortHeader({
+ col,
+ label,
+ sortKey,
+ sortDir,
+ onSort,
+}: {
+ col: SortKey
+ label: string
+ sortKey: SortKey
+ sortDir: 'asc' | 'desc'
+ onSort: (col: SortKey) => void
+}) {
+ const active = sortKey === col
+ const Icon = active
+ ? sortDir === 'asc' ? ArrowUp : ArrowDown
+ : ArrowUpDown
+ return (
+
+ )
+}
+
export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
const router = useRouter()
const [isPending, startTransition] = useTransition()
@@ -76,6 +111,10 @@ export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
const [productFilter, setProductFilter] = useState('all')
const [statusFilter, setStatusFilter] = useState>(new Set())
+ // Sort state
+ const [sortKey, setSortKey] = useState('code')
+ const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc')
+
// Create-form state
const [showCreate, setShowCreate] = useState(false)
const [newTitle, setNewTitle] = useState('')
@@ -84,7 +123,7 @@ export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
const filtered = useMemo(() => {
const q = search.trim().toLowerCase()
- return ideas.filter((idea) => {
+ const result = ideas.filter((idea) => {
if (q && !idea.title.toLowerCase().includes(q)) return false
if (productFilter !== 'all') {
if (productFilter === 'none') {
@@ -99,7 +138,25 @@ export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
if (statusFilter.size > 0 && !statusFilter.has(idea.status)) return false
return true
})
- }, [ideas, search, productFilter, statusFilter])
+ const dir = sortDir === 'asc' ? 1 : -1
+ return [...result].sort((a, b) => {
+ switch (sortKey) {
+ case 'code': return dir * a.code.localeCompare(b.code)
+ case 'title': return dir * a.title.localeCompare(b.title)
+ case 'product': return dir * (a.product?.name ?? '').localeCompare(b.product?.name ?? '')
+ case 'status': return dir * a.status.localeCompare(b.status)
+ }
+ })
+ }, [ideas, search, productFilter, statusFilter, sortKey, sortDir])
+
+ function handleSort(col: SortKey) {
+ if (sortKey === col) {
+ setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'))
+ } else {
+ setSortKey(col)
+ setSortDir('asc')
+ }
+ }
function toggleStatus(s: IdeaStatusApi) {
setStatusFilter((prev) => {
@@ -264,10 +321,10 @@ export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
- Code
- Titel
- Product
- Status
+
+
+
+
Acties