diff --git a/components/jobs/jobs-column.tsx b/components/jobs/jobs-column.tsx index acb0d45..cf19f4a 100644 --- a/components/jobs/jobs-column.tsx +++ b/components/jobs/jobs-column.tsx @@ -1,11 +1,13 @@ 'use client' -import { useEffect, useMemo, useState } from 'react' +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' @@ -82,20 +84,6 @@ function MultiFilterPills({ ) } -function parseCsv(raw: string | null, allowed: Set): Set { - if (!raw) return new Set() - const out = new Set() - for (const part of raw.split(',')) { - const v = part.trim() - if (v && allowed.has(v as T)) out.add(v as T) - } - return out -} - -function setToCsv(s: Set): string { - return Array.from(s).join(',') -} - interface JobsColumnProps { title: string jobs: JobWithRelations[] @@ -115,45 +103,50 @@ export default function JobsColumn({ statusOptions, emptyText, }: JobsColumnProps) { - const kindKey = `${storageKeyPrefix}_filter_kind` - const statusKey = `${storageKeyPrefix}_filter_status` - - const statusValues = useMemo( + const allowedStatuses = useMemo( () => new Set(statusOptions.map((o) => o.value)), - [statusOptions] + [statusOptions], ) + const colPrefs = useUserSettingsStore( + useShallow((s) => s.entities.settings.views?.jobsColumns?.[storageKeyPrefix]), + ) + const setPref = useUserSettingsStore((s) => s.setPref) - const [filterKinds, setFilterKinds] = useState>(() => new Set()) - const [filterStatuses, setFilterStatuses] = useState>(() => new Set()) - const [prefsLoaded, setPrefsLoaded] = useState(false) + 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]) - useEffect(() => { - /* eslint-disable react-hooks/set-state-in-effect */ - setFilterKinds(parseCsv(localStorage.getItem(kindKey), KIND_VALUES)) - setFilterStatuses(parseCsv(localStorage.getItem(statusKey), statusValues)) - setPrefsLoaded(true) - /* eslint-enable react-hooks/set-state-in-effect */ - }, [kindKey, statusKey, statusValues]) + 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]) - useEffect(() => { if (prefsLoaded) localStorage.setItem(kindKey, setToCsv(filterKinds)) }, [filterKinds, prefsLoaded, kindKey]) - useEffect(() => { if (prefsLoaded) localStorage.setItem(statusKey, setToCsv(filterStatuses)) }, [filterStatuses, prefsLoaded, statusKey]) - - function toggleKind(v: ClaudeJobKind) { - setFilterKinds((prev) => { - const next = new Set(prev) - if (next.has(v)) next.delete(v) - else next.add(v) - return next + 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) { - setFilterStatuses((prev) => { - const next = new Set(prev) - if (next.has(v)) next.delete(v) - else next.add(v) - return next - }) + const next = new Set(filterStatuses) + if (next.has(v)) next.delete(v) + else next.add(v) + persist(filterKinds, next) } const filtered = jobs.filter((j) => { @@ -207,14 +200,14 @@ export default function JobsColumn({ options={KIND_OPTIONS} selected={filterKinds} onToggle={toggleKind} - onClear={() => setFilterKinds(new Set())} + onClear={() => persist(new Set(), filterStatuses)} /> setFilterStatuses(new Set())} + onClear={() => persist(filterKinds, new Set())} />