Sprint: ll (#206)
* feat(jobs): voeg lib/jobs-time-filter.ts toe met tijdvenster-predikaat Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(user-settings): voeg views.jobs.timeFilter toe aan UserSettingsSchema Breidt ViewsPrefs uit met een jobs-object (JobsViewPrefs) dat timeFilter accepteert met waarden '1h' | '24h' | 'all'. ViewsPrefs blijft .strict(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(jobs-time-filter): voeg unit-tests toe voor isWithinTimeWindow en UserSettings-schema Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(jobs-time-filter): voeg JobsTimeFilterControl component toe Nieuw client-component dat views.jobs.timeFilter leest/schrijft via useUserSettingsStore met pill-stijl (MD3-tokens). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(jobs): wire JobsTimeFilter in jobs page header Plaatst het tijdfilter-component rechts van de Jobs-kop via justify-between op de header-div. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(jobs): pas tijdvenster-filter toe in JobsColumn Lees views.jobs.timeFilter uit de store en filter jobs op createdAt via isWithinTimeWindow, als eerste check vóór de bestaande kind/status-filters. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ea28a62973
commit
3ad352c10f
7 changed files with 152 additions and 1 deletions
|
|
@ -8,6 +8,7 @@ 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 { isWithinTimeWindow, DEFAULT_JOBS_TIME_FILTER } from '@/lib/jobs-time-filter'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { debugProps } from '@/lib/debug'
|
||||
import type { JobWithRelations } from '@/actions/jobs-page'
|
||||
|
|
@ -112,6 +113,9 @@ export default function JobsColumn({
|
|||
const colPrefs = useUserSettingsStore(
|
||||
useShallow((s) => s.entities.settings.views?.jobsColumns?.[storageKeyPrefix]),
|
||||
)
|
||||
const timeFilter = useUserSettingsStore(
|
||||
useShallow((s) => s.entities.settings.views?.jobs?.timeFilter),
|
||||
) ?? DEFAULT_JOBS_TIME_FILTER
|
||||
const setPref = useUserSettingsStore((s) => s.setPref)
|
||||
|
||||
const filterKinds = useMemo<Set<ClaudeJobKind>>(() => {
|
||||
|
|
@ -152,6 +156,7 @@ export default function JobsColumn({
|
|||
}
|
||||
|
||||
const filtered = jobs.filter((j) => {
|
||||
if (!isWithinTimeWindow(j.createdAt, timeFilter)) return false
|
||||
if (filterKinds.size > 0 && !filterKinds.has(j.kind)) return false
|
||||
if (filterStatuses.size > 0 && !filterStatuses.has(jobStatusToApi(j.status))) return false
|
||||
return true
|
||||
|
|
|
|||
48
components/jobs/jobs-time-filter.tsx
Normal file
48
components/jobs/jobs-time-filter.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
'use client'
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { useUserSettingsStore } from '@/stores/user-settings/store'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { debugProps } from '@/lib/debug'
|
||||
import {
|
||||
JOBS_TIME_FILTER_VALUES,
|
||||
DEFAULT_JOBS_TIME_FILTER,
|
||||
type JobsTimeFilter,
|
||||
} from '@/lib/jobs-time-filter'
|
||||
|
||||
const LABELS: Record<JobsTimeFilter, string> = {
|
||||
'1h': '1 uur',
|
||||
'24h': '24 uur',
|
||||
all: 'Alles',
|
||||
}
|
||||
|
||||
export default function JobsTimeFilterControl() {
|
||||
const current =
|
||||
useUserSettingsStore(
|
||||
useShallow((s) => s.entities.settings.views?.jobs?.timeFilter),
|
||||
) ?? DEFAULT_JOBS_TIME_FILTER
|
||||
const setPref = useUserSettingsStore((s) => s.setPref)
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex items-center gap-1.5"
|
||||
{...debugProps('jobs-time-filter', 'JobsTimeFilter', 'components/jobs/jobs-time-filter.tsx')}
|
||||
>
|
||||
{JOBS_TIME_FILTER_VALUES.map((v) => (
|
||||
<button
|
||||
key={v}
|
||||
type="button"
|
||||
onClick={() => void setPref(['views', 'jobs', 'timeFilter'], v)}
|
||||
className={cn(
|
||||
'text-xs px-2.5 py-1 rounded-full border transition-colors',
|
||||
current === v
|
||||
? 'bg-primary text-primary-foreground border-primary'
|
||||
: 'bg-transparent border-border hover:bg-surface-container',
|
||||
)}
|
||||
>
|
||||
{LABELS[v]}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue