Skip to content

Commit 92fb56d

Browse files
committed
Refactor our multiple booleans into a combined FilterState.
1 parent d889bc1 commit 92fb56d

File tree

1 file changed

+92
-73
lines changed

1 file changed

+92
-73
lines changed

browser-extension/tests/playground/claude.tsx

Lines changed: 92 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ import { useMemo, useState } from 'react'
1919
import type { CommentSpot } from '@/lib/enhancer'
2020
import type { DraftStats } from '@/lib/enhancers/draftStats'
2121

22+
interface FilterState {
23+
hasLink: boolean
24+
hasImage: boolean
25+
hasCode: boolean
26+
sentFilter: 'all' | 'sent' | 'unsent'
27+
searchQuery: string
28+
}
29+
2230
// CVA configuration for stat badges
2331
const statBadge = cva(
2432
'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs font-normal tracking-normal',
@@ -308,47 +316,45 @@ const timeAgo = (date: Date | number) => {
308316
export const ClaudePrototype = () => {
309317
const [drafts] = useState(generateMockDrafts())
310318
const [selectedIds, setSelectedIds] = useState(new Set())
311-
const [hasCodeFilter, setHasCodeFilter] = useState(false)
312-
const [hasImageFilter, setHasImageFilter] = useState(false)
313-
const [hasLinkFilter, setHasLinkFilter] = useState(false)
314-
const [sentFilter, setSentFilter] = useState<'all' | 'sent' | 'unsent'>('all')
315-
const [searchQuery, setSearchQuery] = useState('')
316-
const [sortBy, _setSortBy] = useState('edited-newest')
319+
const [filters, setFilters] = useState<FilterState>({
320+
hasCode: false,
321+
hasImage: false,
322+
hasLink: false,
323+
searchQuery: '',
324+
sentFilter: 'all',
325+
})
326+
327+
const updateFilter = <K extends keyof FilterState>(key: K, value: FilterState[K]) => {
328+
setFilters((prev) => ({ ...prev, [key]: value }))
329+
}
317330
const [showFilters, setShowFilters] = useState(false)
318331

319332
const filteredDrafts = useMemo(() => {
320333
let filtered = [...drafts]
321-
if (hasCodeFilter) {
334+
if (filters.hasCode) {
322335
filtered = filtered.filter((d) => d.latestDraft.stats.codeBlocks.length > 0)
323336
}
324-
if (hasImageFilter) {
337+
if (filters.hasImage) {
325338
filtered = filtered.filter((d) => d.latestDraft.stats.images.length > 0)
326339
}
327-
if (hasLinkFilter) {
340+
if (filters.hasLink) {
328341
filtered = filtered.filter((d) => d.latestDraft.stats.links.length > 0)
329342
}
330-
if (sentFilter !== 'all') {
331-
filtered = filtered.filter((d) => (sentFilter === 'sent' ? d.isSent : !d.isSent))
343+
if (filters.sentFilter !== 'all') {
344+
filtered = filtered.filter((d) => (filters.sentFilter === 'sent' ? d.isSent : !d.isSent))
332345
}
333-
if (searchQuery) {
334-
const query = searchQuery.toLowerCase()
346+
if (filters.searchQuery) {
347+
const query = filters.searchQuery.toLowerCase()
335348
filtered = filtered.filter((d) =>
336349
[d.spot.title, d.latestDraft.content, (d.spot as any).slug, (d.spot as any).subreddit].some(
337350
(value) => value && String(value).toLowerCase().includes(query),
338351
),
339352
)
340353
}
341-
// Sort
342-
switch (sortBy) {
343-
case 'edited-newest':
344-
filtered.sort((a, b) => b.latestDraft.time - a.latestDraft.time)
345-
break
346-
case 'edited-oldest':
347-
filtered.sort((a, b) => a.latestDraft.time - b.latestDraft.time)
348-
break
349-
}
354+
// sort by newest
355+
filtered.sort((a, b) => b.latestDraft.time - a.latestDraft.time)
350356
return filtered
351-
}, [drafts, hasCodeFilter, hasImageFilter, hasLinkFilter, sentFilter, searchQuery, sortBy])
357+
}, [drafts, filters])
352358

353359
const toggleSelection = (id: string) => {
354360
const newSelected = new Set(selectedIds)
@@ -408,7 +414,11 @@ export const ClaudePrototype = () => {
408414

409415
if (
410416
filteredDrafts.length === 0 &&
411-
(searchQuery || hasCodeFilter || hasImageFilter || hasLinkFilter || sentFilter !== 'all')
417+
(filters.searchQuery ||
418+
filters.hasCode ||
419+
filters.hasImage ||
420+
filters.hasLink ||
421+
filters.sentFilter !== 'all')
412422
) {
413423
return (
414424
<div className='min-h-screen bg-white'>
@@ -421,8 +431,8 @@ export const ClaudePrototype = () => {
421431
<input
422432
type='text'
423433
placeholder='Search drafts...'
424-
value={searchQuery}
425-
onChange={(e) => setSearchQuery(e.target.value)}
434+
value={filters.searchQuery}
435+
onChange={(e) => updateFilter('searchQuery', e.target.value)}
426436
className='w-full pl-9 pr-3 py-1.5 border border-gray-300 rounded-md text-sm'
427437
/>
428438
</div>
@@ -434,11 +444,13 @@ export const ClaudePrototype = () => {
434444
<button
435445
type='button'
436446
onClick={() => {
437-
setHasCodeFilter(false)
438-
setHasImageFilter(false)
439-
setHasLinkFilter(false)
440-
setSentFilter('all')
441-
setSearchQuery('')
447+
setFilters({
448+
hasCode: false,
449+
hasImage: false,
450+
hasLink: false,
451+
searchQuery: '',
452+
sentFilter: 'all',
453+
})
442454
}}
443455
className='text-blue-600 hover:underline'
444456
>
@@ -501,8 +513,8 @@ export const ClaudePrototype = () => {
501513
<input
502514
type='text'
503515
placeholder='Search drafts...'
504-
value={searchQuery}
505-
onChange={(e) => setSearchQuery(e.target.value)}
516+
value={filters.searchQuery}
517+
onChange={(e) => updateFilter('searchQuery', e.target.value)}
506518
className='w-full pl-9 pr-3 py-1.5 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500'
507519
/>
508520
</div>
@@ -515,46 +527,7 @@ export const ClaudePrototype = () => {
515527
<Filter className='w-4 h-4 text-gray-600' />
516528
</button>
517529
</div>
518-
{showFilters && (
519-
<div className='absolute top-full right-0 mt-1 p-3 bg-white border border-gray-300 rounded-md shadow-lg z-10 min-w-48'>
520-
<div className='space-y-3'>
521-
<div className='space-y-2'>
522-
<label className='flex items-center gap-2 cursor-pointer'>
523-
<input
524-
type='checkbox'
525-
checked={hasLinkFilter}
526-
onChange={(e) => setHasLinkFilter(e.target.checked)}
527-
className='rounded'
528-
/>
529-
<Badge type='link' />
530-
</label>
531-
<label className='flex items-center gap-2 cursor-pointer'>
532-
<input
533-
type='checkbox'
534-
checked={hasImageFilter}
535-
onChange={(e) => setHasImageFilter(e.target.checked)}
536-
className='rounded'
537-
/>
538-
<Badge type='image' />
539-
</label>
540-
<label className='flex items-center gap-2 cursor-pointer'>
541-
<input
542-
type='checkbox'
543-
checked={hasCodeFilter}
544-
onChange={(e) => setHasCodeFilter(e.target.checked)}
545-
className='rounded'
546-
/>
547-
<Badge type='code' />
548-
</label>
549-
</div>
550-
<div className='flex rounded-md overflow-hidden'>
551-
<Badge type='unsent' />
552-
<Badge type='blank' text='both' />
553-
<Badge type='sent' />
554-
</div>
555-
</div>
556-
</div>
557-
)}
530+
{showFilters && filterControls(filters, updateFilter)}
558531
</div>
559532
</th>
560533
</tr>
@@ -569,6 +542,52 @@ export const ClaudePrototype = () => {
569542
</div>
570543
)
571544
}
545+
function filterControls(
546+
filters: FilterState,
547+
updateFilter: <K extends keyof FilterState>(key: K, value: FilterState[K]) => void,
548+
) {
549+
return (
550+
<div className='absolute top-full right-0 mt-1 p-3 bg-white border border-gray-300 rounded-md shadow-lg z-10 min-w-48'>
551+
<div className='space-y-3'>
552+
<div className='space-y-2'>
553+
<label className='flex items-center gap-2 cursor-pointer'>
554+
<input
555+
type='checkbox'
556+
checked={filters.hasLink}
557+
onChange={(e) => updateFilter('hasLink', e.target.checked)}
558+
className='rounded'
559+
/>
560+
<Badge type='link' />
561+
</label>
562+
<label className='flex items-center gap-2 cursor-pointer'>
563+
<input
564+
type='checkbox'
565+
checked={filters.hasImage}
566+
onChange={(e) => updateFilter('hasImage', e.target.checked)}
567+
className='rounded'
568+
/>
569+
<Badge type='image' />
570+
</label>
571+
<label className='flex items-center gap-2 cursor-pointer'>
572+
<input
573+
type='checkbox'
574+
checked={filters.hasCode}
575+
onChange={(e) => updateFilter('hasCode', e.target.checked)}
576+
className='rounded'
577+
/>
578+
<Badge type='code' />
579+
</label>
580+
</div>
581+
<div className='flex rounded-md overflow-hidden'>
582+
<Badge type='unsent' />
583+
<Badge type='blank' text='both' />
584+
<Badge type='sent' />
585+
</div>
586+
</div>
587+
</div>
588+
)
589+
}
590+
572591
function commentRow(
573592
row: CommentTableRow,
574593
selectedIds: Set<unknown>,

0 commit comments

Comments
 (0)