Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 85x 85x 85x 8x 5x 1x 1x 1x 2x 2x | /**
* FilterSheet Component (Story 4.2 - Task 2b)
*
* Mobile filter sheet (modal) for archive browsing
* Wraps FilterSidebar in a sheet/modal for mobile devices
*/
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FilterSidebar } from './FilterSidebar';
import type { ArchiveFilters } from '@/types/event.types';
import type { Topic } from '@/types/topic.types';
interface FilterSheetProps {
filters: ArchiveFilters;
topics: Topic[];
onFilterChange: (filters: ArchiveFilters) => void;
onClearFilters: () => void;
onSortChange: (sort: string) => void;
currentSort: string;
loading?: boolean;
}
export function FilterSheet({
filters,
topics,
onFilterChange,
onClearFilters,
onSortChange,
currentSort,
loading = false,
}: FilterSheetProps) {
const { t } = useTranslation();
const [isOpen, setIsOpen] = useState(false);
return (
<div data-testid="filter-sheet">
{/* Trigger Button */}
<button
onClick={() => setIsOpen(true)}
className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
data-testid="filter-sheet-trigger"
>
{t('archive.filters.title')}
</button>
{/* Modal Overlay */}
{isOpen && (
<div
className="fixed inset-0 z-50 flex items-end justify-center bg-black bg-opacity-50"
onClick={() => setIsOpen(false)}
>
{/* Sheet */}
<div
className="bg-background text-foreground w-full max-h-[80vh] rounded-t-lg overflow-y-auto p-6"
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center mb-4">
<h2 className="text-lg font-semibold">{t('archive.filters.title')}</h2>
<button
onClick={() => setIsOpen(false)}
className="text-muted-foreground hover:text-foreground"
>
✕
</button>
</div>
{/* Filter Content.
onFilterChange must NOT auto-close the sheet: FilterSidebar fires it on
mount (300 ms-debounced search effect) and on every topic toggle, which
used to close the sheet the moment the user opened it. The sheet now
stays open until the user explicitly closes via the ✕ button or the
backdrop, so multiple topics can be selected in one go. Sort and Clear
remain one-shot actions that close the sheet after applying. */}
<FilterSidebar
filters={filters}
topics={topics}
onFilterChange={onFilterChange}
onClearFilters={() => {
onClearFilters();
setIsOpen(false);
}}
onSortChange={(s) => {
onSortChange(s);
setIsOpen(false);
}}
currentSort={currentSort}
loading={loading}
/>
</div>
</div>
)}
</div>
);
}
|