feat(ideas): vervang inline statuschips door IdeasFilterPopover met user-settings persistentie
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b8eb724d17
commit
e398b84930
1 changed files with 26 additions and 28 deletions
|
|
@ -12,6 +12,10 @@ import { useMemo, useState, useTransition } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { Plus, ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react'
|
import { Plus, ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
|
import { useShallow } from 'zustand/react/shallow'
|
||||||
|
|
||||||
|
import { useUserSettingsStore } from '@/stores/user-settings/store'
|
||||||
|
import { IdeasFilterPopover } from '@/components/ideas/ideas-filter-popover'
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
|
|
@ -122,7 +126,11 @@ export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
|
||||||
// Filter state
|
// Filter state
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const [productFilter, setProductFilter] = useState<string>('all')
|
const [productFilter, setProductFilter] = useState<string>('all')
|
||||||
const [statusFilter, setStatusFilter] = useState<Set<IdeaStatusApi>>(new Set())
|
const filterStatuses = useUserSettingsStore(useShallow(
|
||||||
|
(s) => s.entities.settings.views?.ideasList?.filterStatuses ?? []))
|
||||||
|
const setPref = useUserSettingsStore((s) => s.setPref)
|
||||||
|
const statusFilter = useMemo(() => new Set(filterStatuses), [filterStatuses])
|
||||||
|
const [filterPopoverOpen, setFilterPopoverOpen] = useState(false)
|
||||||
|
|
||||||
// Sort state
|
// Sort state
|
||||||
const [sortKey, setSortKey] = useState<SortKey>('code')
|
const [sortKey, setSortKey] = useState<SortKey>('code')
|
||||||
|
|
@ -197,12 +205,14 @@ export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleStatus(s: IdeaStatusApi) {
|
function toggleStatus(s: IdeaStatusApi) {
|
||||||
setStatusFilter((prev) => {
|
const next = filterStatuses.includes(s)
|
||||||
const next = new Set(prev)
|
? filterStatuses.filter((v) => v !== s)
|
||||||
if (next.has(s)) next.delete(s)
|
: [...filterStatuses, s]
|
||||||
else next.add(s)
|
void setPref(['views', 'ideasList', 'filterStatuses'], next)
|
||||||
return next
|
}
|
||||||
})
|
|
||||||
|
function clearStatusFilter() {
|
||||||
|
void setPref(['views', 'ideasList', 'filterStatuses'], [])
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCreate() {
|
function handleCreate() {
|
||||||
|
|
@ -289,6 +299,15 @@ export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<div className="ml-auto flex items-center gap-2">
|
<div className="ml-auto flex items-center gap-2">
|
||||||
|
<IdeasFilterPopover
|
||||||
|
open={filterPopoverOpen}
|
||||||
|
onOpenChange={setFilterPopoverOpen}
|
||||||
|
statusOptions={STATUS_FILTERS}
|
||||||
|
selected={statusFilter}
|
||||||
|
onToggle={toggleStatus}
|
||||||
|
onClear={clearStatusFilter}
|
||||||
|
activeFilterCount={statusFilter.size}
|
||||||
|
/>
|
||||||
<DemoTooltip show={isDemo}>
|
<DemoTooltip show={isDemo}>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -313,27 +332,6 @@ export function IdeaList({ ideas, products, isDemo }: IdeaListProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Status-chips als multi-select filter */}
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
{STATUS_FILTERS.map((s) => {
|
|
||||||
const active = statusFilter.has(s.value)
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={s.value}
|
|
||||||
type="button"
|
|
||||||
onClick={() => toggleStatus(s.value)}
|
|
||||||
className={`rounded-full border px-2.5 py-0.5 text-xs transition-colors ${
|
|
||||||
active
|
|
||||||
? 'bg-primary text-on-primary border-primary'
|
|
||||||
: 'bg-background text-muted-foreground border-input hover:bg-muted'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{s.label}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Snel idee form — geen product-dropdown */}
|
{/* Snel idee form — geen product-dropdown */}
|
||||||
{showQuick && (
|
{showQuick && (
|
||||||
<div className="rounded-md border border-input bg-surface-container p-4 space-y-3">
|
<div className="rounded-md border border-input bg-surface-container p-4 space-y-3">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue